Merge branch 'master' into fixescorsswagger

This commit is contained in:
Benedikt-Alexander Mokroß 2019-10-15 07:23:31 +02:00
commit 2c33ef4c8e
61 changed files with 1524 additions and 629 deletions

View File

@ -84,10 +84,11 @@ add_library(oatpp
oatpp/core/data/mapping/type/Primitive.hpp
oatpp/core/data/mapping/type/Type.cpp
oatpp/core/data/mapping/type/Type.hpp
oatpp/core/data/share/LazyStringMap.hpp
oatpp/core/data/share/MemoryLabel.cpp
oatpp/core/data/share/MemoryLabel.hpp
oatpp/core/data/stream/BufferInputStream.cpp
oatpp/core/data/stream/BufferInputStream.hpp
oatpp/core/data/stream/BufferStream.cpp
oatpp/core/data/stream/BufferStream.hpp
oatpp/core/data/stream/ChunkedBuffer.cpp
oatpp/core/data/stream/ChunkedBuffer.hpp
oatpp/core/data/stream/FileStream.cpp

View File

@ -220,6 +220,8 @@ CoroutineHandle::~CoroutineHandle() {
Action CoroutineHandle::takeAction(Action&& action) {
//v_int32 iterations = 0;
while (true) {
switch (action.m_type) {
@ -245,9 +247,18 @@ Action CoroutineHandle::takeAction(Action&& action) {
case Action::TYPE_YIELD_TO: {
_FP = action.m_data.fptr;
//break;
return std::forward<oatpp::async::Action>(action);
}
// case Action::TYPE_REPEAT: {
// break;
// }
//
// case Action::TYPE_IO_REPEAT: {
// break;
// }
case Action::TYPE_ERROR: {
Action newAction = _CP->handleError(action.m_data.error);
@ -277,6 +288,9 @@ Action CoroutineHandle::takeAction(Action&& action) {
};
// action = iterate();
// ++ iterations;
}
return std::forward<oatpp::async::Action>(action);

View File

@ -78,13 +78,14 @@ void Executor::SubmissionProcessor::detach() {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Executor
Executor::Executor(v_int32 processorWorkersCount, v_int32 ioWorkersCount, v_int32 timerWorkersCount, bool useIOEventWorker)
Executor::Executor(v_int32 processorWorkersCount, v_int32 ioWorkersCount, v_int32 timerWorkersCount, v_int32 ioWorkerType)
: m_balancer(0)
{
processorWorkersCount = chooseProcessorWorkersCount(processorWorkersCount);
ioWorkersCount = chooseIOWorkersCount(processorWorkersCount, ioWorkersCount);
timerWorkersCount = chooseTimerWorkersCount(timerWorkersCount);
ioWorkerType = chooseIOWorkerType(ioWorkerType);
for(v_int32 i = 0; i < processorWorkersCount; i ++) {
m_processorWorkers.push_back(std::make_shared<SubmissionProcessor>());
@ -93,14 +94,26 @@ Executor::Executor(v_int32 processorWorkersCount, v_int32 ioWorkersCount, v_int3
m_allWorkers.insert(m_allWorkers.end(), m_processorWorkers.begin(), m_processorWorkers.end());
std::vector<std::shared_ptr<worker::Worker>> ioWorkers;
if(useIOEventWorker) {
for (v_int32 i = 0; i < ioWorkersCount; i++) {
ioWorkers.push_back(std::make_shared<worker::IOEventWorkerForeman>());
switch(ioWorkerType) {
case IO_WORKER_TYPE_NAIVE: {
for (v_int32 i = 0; i < ioWorkersCount; i++) {
ioWorkers.push_back(std::make_shared<worker::IOWorker>());
}
break;
}
} else {
for (v_int32 i = 0; i < ioWorkersCount; i++) {
ioWorkers.push_back(std::make_shared<worker::IOWorker>());
case IO_WORKER_TYPE_EVENT: {
for (v_int32 i = 0; i < ioWorkersCount; i++) {
ioWorkers.push_back(std::make_shared<worker::IOEventWorkerForeman>());
}
break;
}
default:
throw std::runtime_error("[oatpp::async::Executor::Executor()]: Error. Unknown IO worker type.");
}
linkWorkers(ioWorkers);
@ -148,6 +161,20 @@ v_int32 Executor::chooseTimerWorkersCount(v_int32 timerWorkersCount) {
throw std::runtime_error("[oatpp::async::Executor::chooseTimerWorkersCount()]: Error. Invalid timer workers count specified.");
}
v_int32 Executor::chooseIOWorkerType(v_int32 ioWorkerType) {
if(ioWorkerType == VALUE_SUGGESTED) {
#if defined(WIN32) || defined(_WIN32)
return IO_WORKER_TYPE_NAIVE;
#else
return IO_WORKER_TYPE_EVENT;
#endif
}
return ioWorkerType;
}
void Executor::linkWorkers(const std::vector<std::shared_ptr<worker::Worker>>& workers) {
m_allWorkers.insert(m_allWorkers.end(), workers.begin(), workers.end());

View File

@ -84,6 +84,17 @@ public:
* Special value to indicate that Executor should choose it's own the value of specified parameter.
*/
static constexpr const v_int32 VALUE_SUGGESTED = -1000;
public:
/**
* IO Worker type naive.
*/
static constexpr const v_int32 IO_WORKER_TYPE_NAIVE = 0;
/**
* IO Worker type event.
*/
static constexpr const v_int32 IO_WORKER_TYPE_EVENT = 1;
private:
std::atomic<v_word32> m_balancer;
private:
@ -93,6 +104,7 @@ private:
static v_int32 chooseProcessorWorkersCount(v_int32 processorWorkersCount);
static v_int32 chooseIOWorkersCount(v_int32 processorWorkersCount, v_int32 ioWorkersCount);
static v_int32 chooseTimerWorkersCount(v_int32 timerWorkersCount);
static v_int32 chooseIOWorkerType(v_int32 ioWorkerType);
void linkWorkers(const std::vector<std::shared_ptr<worker::Worker>>& workers);
public:
@ -101,16 +113,12 @@ public:
* @param processorWorkersCount - number of data processing workers.
* @param ioWorkersCount - number of I/O processing workers.
* @param timerWorkersCount - number of timer processing workers.
* @param IOWorkerType
*/
Executor(v_int32 processorWorkersCount = VALUE_SUGGESTED,
v_int32 ioWorkersCount = VALUE_SUGGESTED,
v_int32 timerWorkersCount = VALUE_SUGGESTED,
#if defined(WIN32) || defined(_WIN32)
bool useIOEventWorker = false
#else
bool useIOEventWorker = true
#endif
);
v_int32 ioWorkerType = VALUE_SUGGESTED);
/**
* Non-virtual Destructor.

View File

@ -0,0 +1,207 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* 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_data_share_LazyStringMap_hpp
#define oatpp_data_share_LazyStringMap_hpp
#include "./MemoryLabel.hpp"
#include <unordered_map>
namespace oatpp { namespace data { namespace share {
/**
* Lazy String Map keeps keys, and values as memory label.
* Once value is requested by user, the new memory block is allocated and value is copied to be stored permanently.
* @tparam Key - one of: &id:oatpp::data::share::MemoryLabel;, &id:oatpp::data::share::StringKeyLabel;, &id:oatpp::data::share::StringKeyLabelCI;,
* &id:oatpp::data::share::StringKeyLabelCI_FAST;.
*/
template<class Key>
class LazyStringMap {
private:
mutable bool m_fullyInitialized;
std::unordered_map<Key, StringKeyLabel> m_map;
public:
/**
* Constructor.
*/
LazyStringMap()
: m_fullyInitialized(false)
{}
/**
* Default copy-constructor.
* @param other
*/
LazyStringMap(const LazyStringMap& other) = default;
/**
* Move constructor.
* @param other
*/
LazyStringMap(LazyStringMap&& other)
: m_fullyInitialized(false)
, m_map(std::move(other.m_map))
{}
LazyStringMap& operator = (LazyStringMap& other) = default;
LazyStringMap& operator = (LazyStringMap&& other){
m_fullyInitialized = false;
m_map = std::move(other.m_map);
return *this;
}
/**
* Put value to map.
* @param key
* @param value
*/
void put(const Key& key, const StringKeyLabel& value) {
m_map.insert({key, value});
m_fullyInitialized = false;
}
/**
* Put value to map if not already exists.
* @param key
* @param value
* @return
*/
bool putIfNotExists(const Key& key, const StringKeyLabel& value) {
auto it = m_map.find(key);
if(it == m_map.end()) {
m_map.insert({key, value});
m_fullyInitialized = false;
return true;
}
return false;
}
/**
* Get value as &id:oatpp::String;.
* @param key
* @return
*/
oatpp::String get(const Key& key) const {
auto it = m_map.find(key);
if(it != m_map.end()) {
it->second.captureToOwnMemory();
return it->second.getMemoryHandle();
}
return nullptr;
}
/**
* Get value as a memory label.
* @tparam T - one of: &id:oatpp::data::share::MemoryLabel;, &id:oatpp::data::share::StringKeyLabel;, &id:oatpp::data::share::StringKeyLabelCI;,
* &id:oatpp::data::share::StringKeyLabelCI_FAST;.
* @param key
* @return
*/
template<class T>
T getAsMemoryLabel(const Key& key) const {
auto it = m_map.find(key);
if(it != m_map.end()) {
it->second.captureToOwnMemory();
const auto& label = it->second;
return T(label.getMemoryHandle(), label.getData(), label.getSize());
}
return T(nullptr, nullptr, 0);
}
/**
* Get value as a memory label without allocating memory for value.
* @tparam T - one of: &id:oatpp::data::share::MemoryLabel;, &id:oatpp::data::share::StringKeyLabel;, &id:oatpp::data::share::StringKeyLabelCI;,
* &id:oatpp::data::share::StringKeyLabelCI_FAST;.
* @param key
* @return
*/
template<class T>
T getAsMemoryLabel_Unsafe(const Key& key) const {
auto it = m_map.find(key);
if(it != m_map.end()) {
const auto& label = it->second;
return T(label.getMemoryHandle(), label.getData(), label.getSize());
}
return T(nullptr, nullptr, 0);
}
/**
* Get map of all values.
* @return
*/
const std::unordered_map<Key, StringKeyLabel>& getAll() const {
if(!m_fullyInitialized) {
for(auto& pair : m_map) {
pair.first.captureToOwnMemory();
pair.second.captureToOwnMemory();
}
m_fullyInitialized = true;
}
return m_map;
}
/**
* Get map of all values without allocating memory for those keys/values.
* @return
*/
const std::unordered_map<Key, StringKeyLabel>& getAll_Unsafe() const {
return m_map;
}
/**
* Get number of entries in the map.
* @return
*/
v_int32 getSize() const {
return (v_int32) m_map.size();
}
};
}}}
#endif //oatpp_data_share_LazyStringMap_hpp

View File

@ -37,8 +37,8 @@ namespace oatpp { namespace data { namespace share {
*/
class MemoryLabel {
protected:
std::shared_ptr<base::StrBuffer> m_memoryHandle;
p_char8 m_data;
mutable std::shared_ptr<base::StrBuffer> m_memoryHandle;
mutable p_char8 m_data;
v_int32 m_size;
public:
@ -89,6 +89,16 @@ public:
return m_memoryHandle;
}
/**
* Capture data referenced by memory label to its own memory.
*/
void captureToOwnMemory() const {
if(!m_memoryHandle || m_memoryHandle->getData() != m_data || m_memoryHandle->getSize() != m_size) {
m_memoryHandle.reset(new base::StrBuffer(m_data, m_size, true));
m_data = m_memoryHandle->getData();
}
}
/**
* Check if labeled data equals to data specified.
* Data is compared using &id:oatpp::base::StrBuffer::equals;.
@ -126,6 +136,10 @@ public:
std::string std_str() const {
return std::string((const char*) m_data, m_size);
}
explicit operator bool() const {
return m_data != nullptr;
}
};

View File

@ -1,109 +0,0 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* 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 "BufferInputStream.hpp"
namespace oatpp { namespace data{ namespace stream {
BufferInputStream::BufferInputStream(const std::shared_ptr<base::StrBuffer>& memoryHandle, p_char8 data, v_io_size size)
: m_memoryHandle(memoryHandle)
, m_data(data)
, m_size(size)
, m_position(0)
, 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<base::StrBuffer>& 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) {
desiredAmount = m_size - m_position;
}
std::memcpy(data, &m_data[m_position], desiredAmount);
m_position += desiredAmount;
return desiredAmount;
}
oatpp::async::Action BufferInputStream::suggestInputStreamAction(data::v_io_size ioResult) {
if(ioResult > 0) {
return oatpp::async::Action::createActionByType(oatpp::async::Action::TYPE_REPEAT);
}
OATPP_LOGE("[oatpp::data::stream::BufferInputStream::suggestInputStreamAction()]", "Error. ioResult=%d", ioResult);
const char* message =
"Error. BufferInputStream::suggestOutputStreamAction() method is called with (ioResult <= 0).\n"
"Conceptual error.";
throw std::runtime_error(message);
}
void BufferInputStream::setInputStreamIOMode(IOMode ioMode) {
m_ioMode = ioMode;
}
IOMode BufferInputStream::getInputStreamIOMode() {
return m_ioMode;
}
std::shared_ptr<base::StrBuffer> BufferInputStream::getDataMemoryHandle() {
return m_memoryHandle;
}
p_char8 BufferInputStream::getData() {
return m_data;
}
v_io_size BufferInputStream::getDataSize() {
return m_size;
}
v_io_size BufferInputStream::getCurrentPosition() {
return m_position;
}
void BufferInputStream::setCurrentPosition(v_io_size position) {
m_position = position;
}
}}}

View File

@ -0,0 +1,238 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* 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 "BufferStream.hpp"
namespace oatpp { namespace data{ namespace stream {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BufferOutputStream
BufferOutputStream::BufferOutputStream(v_io_size initialCapacity, v_io_size growBytes)
: m_data(new v_char8[initialCapacity])
, m_capacity(initialCapacity)
, m_position(0)
, m_growBytes(growBytes)
, m_ioMode(IOMode::NON_BLOCKING)
{}
BufferOutputStream::~BufferOutputStream() {
delete [] m_data;
}
data::v_io_size BufferOutputStream::write(const void *data, data::v_io_size count) {
reserveBytesUpfront(count);
std::memcpy(m_data + m_position, data, count);
m_position += count;
return count;
}
void BufferOutputStream::setOutputStreamIOMode(IOMode ioMode) {
m_ioMode = ioMode;
}
IOMode BufferOutputStream::getOutputStreamIOMode() {
return m_ioMode;
}
void BufferOutputStream::reserveBytesUpfront(v_io_size count) {
if(m_position + count > m_capacity) {
if(m_growBytes <= 0) {
throw std::runtime_error("[oatpp::data::stream::BufferOutputStream::reserveBytesUpfront()]: Error. Buffer was not allowed to grow.");
}
data::v_io_size extraNeeded = m_position + count - m_capacity;
data::v_io_size extraChunks = extraNeeded / m_growBytes;
if(extraChunks * m_growBytes < extraNeeded) {
extraChunks ++;
}
data::v_io_size newCapacity = m_capacity + extraChunks * m_growBytes;
p_char8 newData = new v_char8[newCapacity];
std::memcpy(newData, m_data, m_position);
delete [] m_data;
m_data = newData;
m_capacity = newCapacity;
}
}
p_char8 BufferOutputStream::getData() {
return m_data;
}
v_io_size BufferOutputStream::getCapacity() {
return m_capacity;
}
v_io_size BufferOutputStream::getCurrentPosition() {
return m_position;
}
void BufferOutputStream::setCurrentPosition(v_io_size position) {
m_position = position;
}
oatpp::String BufferOutputStream::toString() {
return oatpp::String((const char*)m_data, m_position, true);
}
oatpp::String BufferOutputStream::getSubstring(data::v_io_size pos, data::v_io_size count) {
if(pos + count <= m_position) {
return oatpp::String((const char *) (m_data + pos), count, true);
} else {
return oatpp::String((const char *) (m_data + pos), m_position - pos, true);
}
}
oatpp::data::v_io_size BufferOutputStream::flushToStream(OutputStream* stream) {
return oatpp::data::stream::writeExactSizeData(stream, m_data, m_position);
}
oatpp::async::CoroutineStarter BufferOutputStream::flushToStreamAsync(const std::shared_ptr<BufferOutputStream>& _this, const std::shared_ptr<OutputStream>& stream) {
class WriteDataCoroutine : public oatpp::async::Coroutine<WriteDataCoroutine> {
private:
std::shared_ptr<BufferOutputStream> m_this;
std::shared_ptr<oatpp::data::stream::OutputStream> m_stream;
AsyncInlineWriteData m_inlineData;
public:
WriteDataCoroutine(const std::shared_ptr<BufferOutputStream>& _this,
const std::shared_ptr<oatpp::data::stream::OutputStream>& stream)
: m_this(_this)
, m_stream(stream)
{}
Action act() {
if(m_inlineData.currBufferPtr == nullptr) {
m_inlineData.currBufferPtr = m_this->m_data;
m_inlineData.bytesLeft = m_this->m_position;
}
return writeExactSizeDataAsyncInline(m_stream.get(), m_inlineData, finish());
}
};
return WriteDataCoroutine::start(_this, stream);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BufferInputStream
BufferInputStream::BufferInputStream(const std::shared_ptr<base::StrBuffer>& memoryHandle, p_char8 data, v_io_size size)
: m_memoryHandle(memoryHandle)
, m_data(data)
, m_size(size)
, m_position(0)
, 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<base::StrBuffer>& 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) {
desiredAmount = m_size - m_position;
}
std::memcpy(data, &m_data[m_position], desiredAmount);
m_position += desiredAmount;
return desiredAmount;
}
oatpp::async::Action BufferInputStream::suggestInputStreamAction(data::v_io_size ioResult) {
if(ioResult > 0) {
return oatpp::async::Action::createActionByType(oatpp::async::Action::TYPE_REPEAT);
}
OATPP_LOGE("[oatpp::data::stream::BufferInputStream::suggestInputStreamAction()]", "Error. ioResult=%d", ioResult);
const char* message =
"Error. BufferInputStream::suggestOutputStreamAction() method is called with (ioResult <= 0).\n"
"Conceptual error.";
throw std::runtime_error(message);
}
void BufferInputStream::setInputStreamIOMode(IOMode ioMode) {
m_ioMode = ioMode;
}
IOMode BufferInputStream::getInputStreamIOMode() {
return m_ioMode;
}
std::shared_ptr<base::StrBuffer> BufferInputStream::getDataMemoryHandle() {
return m_memoryHandle;
}
p_char8 BufferInputStream::getData() {
return m_data;
}
v_io_size BufferInputStream::getDataSize() {
return m_size;
}
v_io_size BufferInputStream::getCurrentPosition() {
return m_position;
}
void BufferInputStream::setCurrentPosition(v_io_size position) {
m_position = position;
}
}}}

View File

@ -22,13 +22,120 @@
*
***************************************************************************/
#ifndef oatpp_data_stream_BufferInputStream_hpp
#define oatpp_data_stream_BufferInputStream_hpp
#ifndef oatpp_data_stream_BufferStream_hpp
#define oatpp_data_stream_BufferStream_hpp
#include "Stream.hpp"
namespace oatpp { namespace data{ namespace stream {
/**
* BufferOutputStream
*/
class BufferOutputStream : public ConsistentOutputStream {
private:
p_char8 m_data;
v_io_size m_capacity;
v_io_size m_position;
v_io_size m_growBytes;
IOMode m_ioMode;
public:
/**
* Constructor.
* @param growBytes
*/
BufferOutputStream(v_io_size initialCapacity = 2048, v_io_size growBytes = 2048);
/**
* Virtual destructor.
*/
~BufferOutputStream();
/**
* Write `count` of bytes to stream.
* @param data - data to write.
* @param count - number of bytes to write.
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;.
*/
data::v_io_size write(const void *data, data::v_io_size count) override;
/**
* Set stream I/O mode.
* @throws
*/
void setOutputStreamIOMode(IOMode ioMode) override;
/**
* Get stream I/O mode.
* @return
*/
IOMode getOutputStreamIOMode() override;
/**
* Reserve bytes for future writes.
*/
void reserveBytesUpfront(v_io_size count);
/**
* Get pointer to data.
* @return - pointer to data.
*/
p_char8 getData();
/**
* Get current capacity.
* Capacity may change.
* @return
*/
v_io_size getCapacity();
/**
* Get current data write position.
* @return - current data write position.
*/
v_io_size getCurrentPosition();
/**
* Set current data write position.
* @param position - data write position.
*/
void setCurrentPosition(v_io_size position);
/**
* Copy data to &id:oatpp::String;.
* @return
*/
oatpp::String toString();
/**
* Create &id:oatpp::String; from part of buffer.
* @param pos - starting position in buffer.
* @param count - size of bytes to write to substring.
* @return - &id:oatpp::String;
*/
oatpp::String getSubstring(data::v_io_size pos, data::v_io_size count);
/**
* Write all bytes from buffer to stream.
* @param stream - stream to flush all data to.
* @return - actual amount of bytes flushed.
*/
oatpp::data::v_io_size flushToStream(OutputStream* stream);
/**
* Write all bytes from buffer to stream in async manner.
* @param _this - pointer to `this` buffer.
* @param stream - stream to flush all data to.
* @return - &id:oatpp::async::CoroutineStarter;.
*/
static oatpp::async::CoroutineStarter flushToStreamAsync(const std::shared_ptr<BufferOutputStream>& _this, const std::shared_ptr<OutputStream>& stream);
};
/**
* BufferInputStream
*/
class BufferInputStream : public InputStream {
private:
std::shared_ptr<base::StrBuffer> m_memoryHandle;
@ -131,4 +238,4 @@ public:
}}}
#endif // oatpp_data_stream_BufferInputStream_hpp
#endif // oatpp_data_stream_BufferStream_hpp

View File

@ -188,10 +188,6 @@ public:
*/
data::v_io_size readSubstring(void *buffer, data::v_io_size pos, data::v_io_size count);
/**
* Create &id:oatpp::String; from part of ChunkedBuffer.
*/
/**
* Create &id:oatpp::String; from part of ChunkedBuffer.
* @param pos - starting position in ChunkedBuffer.

View File

@ -135,7 +135,9 @@ v_int32 Caret::StateSaveGuard::getSavedErrorCode() {
Caret::Caret(const oatpp::String& str)
: Caret(str->getData(), str->getSize())
{}
{
m_dataMemoryHandle = str.getPtr();
}
std::shared_ptr<Caret> Caret::createShared(const char* text){
return std::make_shared<Caret>(text);
@ -163,7 +165,11 @@ v_int32 Caret::StateSaveGuard::getSavedErrorCode() {
v_int32 Caret::getDataSize(){
return m_size;
}
std::shared_ptr<oatpp::base::StrBuffer> Caret::getDataMemoryHandle() {
return m_dataMemoryHandle;
}
void Caret::setPosition(v_int32 position){
m_pos = position;
}

View File

@ -152,6 +152,7 @@ private:
v_int32 m_pos;
const char* m_errorMessage;
v_int32 m_errorCode;
std::shared_ptr<oatpp::base::StrBuffer> m_dataMemoryHandle;
public:
Caret(const char* text);
Caret(p_char8 parseData, v_int32 dataSize);
@ -182,6 +183,12 @@ public:
*/
v_int32 getDataSize();
/**
* Get data memoryHandle.
* @return
*/
std::shared_ptr<oatpp::base::StrBuffer> getDataMemoryHandle();
/**
* Set caret position relative to data
* @param position

View File

@ -103,10 +103,10 @@ oatpp::String Url::Parser::parsePath(oatpp::parser::Caret& caret) {
return nullptr;
}
void Url::Parser::parseQueryParamsToMap(Url::Parameters& params, oatpp::parser::Caret& caret) {
void Url::Parser::parseQueryParams(Url::Parameters& params, oatpp::parser::Caret& caret) {
if(caret.findChar('?')) {
do {
caret.inc();
auto nameLabel = caret.putLabel();
@ -116,60 +116,32 @@ void Url::Parser::parseQueryParamsToMap(Url::Parameters& params, oatpp::parser::
caret.inc();
auto valueLabel = caret.putLabel();
caret.findChar('&');
params[nameLabel.toString()] = valueLabel.toString();
params.put(StringKeyLabel(caret.getDataMemoryHandle(), nameLabel.getData(), nameLabel.getSize()),
StringKeyLabel(caret.getDataMemoryHandle(), valueLabel.getData(), valueLabel.getSize()));
} else {
params[nameLabel.toString()] = oatpp::String("", false);
params.put(StringKeyLabel(caret.getDataMemoryHandle(), nameLabel.getData(), nameLabel.getSize()), "");
}
} while (caret.canContinueAtChar('&'));
}
}
void Url::Parser::parseQueryParamsToMap(Url::Parameters& params, const oatpp::String& str) {
void Url::Parser::parseQueryParams(Url::Parameters& params, const oatpp::String& str) {
oatpp::parser::Caret caret(str.getPtr());
parseQueryParamsToMap(params, caret);
parseQueryParams(params, caret);
}
Url::Parameters Url::Parser::parseQueryParams(oatpp::parser::Caret& caret) {
Url::Parameters params;
parseQueryParamsToMap(params, caret);
return params;
parseQueryParams(params, caret);
return std::move(params);
}
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;
parseQueryParams(params, str);
return std::move(params);
}
Url Url::Parser::parseUrl(oatpp::parser::Caret& caret) {

View File

@ -25,13 +25,11 @@
#ifndef oatpp_network_Url_hpp
#define oatpp_network_Url_hpp
#include "oatpp/core/data/share/MemoryLabel.hpp"
#include "oatpp/core/data/share/LazyStringMap.hpp"
#include "oatpp/core/parser/Caret.hpp"
#include "oatpp/core/collection/ListMap.hpp"
#include "oatpp/core/Types.hpp"
#include <unordered_map>
namespace oatpp { namespace network {
@ -48,13 +46,8 @@ public:
/**
* Parameters - map string to string.
*/
typedef std::unordered_map<oatpp::String, oatpp::String> Parameters;
typedef oatpp::data::share::LazyStringMap<oatpp::data::share::StringKeyLabel> Parameters;
/**
* Parameters as &id:oatpp::data::share::StringKeyLabel;.
* Advantage of oatpp::data::share::StringKeyLabel - is that there is no memory allocations needed to create "Memory Label".
*/
typedef std::unordered_map<StringKeyLabel, StringKeyLabel> ParametersAsLabels;
public:
/**
@ -111,13 +104,13 @@ public:
* parse query params in form of `"?<paramName>=<paramValue>&<paramName>=<paramValue>..."` referred by ParsingCaret
* and put that params to Parameters map
*/
static void parseQueryParamsToMap(Url::Parameters& params, oatpp::parser::Caret& caret);
static void parseQueryParams(Url::Parameters& params, oatpp::parser::Caret& caret);
/**
* parse query params in form of `"?<paramName>=<paramValue>&<paramName>=<paramValue>..."` referred by str
* and put that params to Parameters map
*/
static void parseQueryParamsToMap(Url::Parameters& params, const oatpp::String& str);
static void parseQueryParams(Url::Parameters& params, const oatpp::String& str);
/**
* parse query params in form of `"?<paramName>=<paramValue>&<paramName>=<paramValue>..."` referred by ParsingCaret
@ -129,14 +122,6 @@ public:
*/
static Url::Parameters parseQueryParams(const oatpp::String& str);
/**
* Same as parseQueryParams() but use StringKeyLabel instead of a String.
* Zero allocations. Use this method for better performance.
* @param str
* @return `std::unordered_map<StringKeyLabel, StringKeyLabel>`. See &l:Url::StringKeyLabel;.
*/
static ParametersAsLabels labelQueryParams(const oatpp::String& str);
/**
* Parse Url
* @param caret

View File

@ -118,11 +118,11 @@ oatpp::web::protocol::http::Headers ApiClient::convertParamsMap(const std::share
auto curr = params->getFirstEntry();
while (curr != nullptr) {
result[curr->getKey()] = oatpp::utils::conversion::primitiveToStr(curr->getValue());
result.put(curr->getKey(), oatpp::utils::conversion::primitiveToStr(curr->getValue()));
curr = curr->getNext();
}
}
return result;
return std::move(result);
}
oatpp::String ApiClient::formatPath(const PathPattern& pathPattern,

View File

@ -158,6 +158,8 @@ HttpRequestExecutor::executeAsync(const String& method,
typedef protocol::http::incoming::ResponseHeadersReader ResponseHeadersReader;
class ExecutorCoroutine : public oatpp::async::CoroutineWithResult<ExecutorCoroutine, const std::shared_ptr<HttpRequestExecutor::Response>&> {
private:
typedef oatpp::web::protocol::http::outgoing::Request OutgoingRequest;
private:
std::shared_ptr<oatpp::network::ClientConnectionProvider> m_connectionProvider;
String m_method;
@ -202,12 +204,12 @@ HttpRequestExecutor::executeAsync(const String& method,
/* Because there is a call to it from act() in synchronous manner */
Action onConnectionReady(const std::shared_ptr<oatpp::data::stream::IOStream>& connection) {
m_connection = connection;
auto request = oatpp::web::protocol::http::outgoing::Request::createShared(m_method, m_path, m_headers, m_body);
auto request = OutgoingRequest::createShared(m_method, m_path, m_headers, m_body);
request->putHeaderIfNotExists(Header::HOST, m_connectionProvider->getProperty("host"));
request->putHeaderIfNotExists(Header::CONNECTION, Header::Value::CONNECTION_KEEP_ALIVE);
m_buffer = oatpp::data::share::MemoryLabel(oatpp::base::StrBuffer::createShared(oatpp::data::buffer::IOBuffer::BUFFER_SIZE));
m_upstream = oatpp::data::stream::OutputStreamBufferedProxy::createShared(connection, m_buffer);
return request->sendAsync(m_upstream).next(m_upstream->flushAsync()).next(yieldTo(&ExecutorCoroutine::readResponse));
return OutgoingRequest::sendAsync(request, m_upstream).next(m_upstream->flushAsync()).next(yieldTo(&ExecutorCoroutine::readResponse));
}
Action readResponse() {

View File

@ -24,7 +24,7 @@
#include "InMemoryPartReader.hpp"
#include "oatpp/core/data/stream/BufferInputStream.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
namespace oatpp { namespace web { namespace mime { namespace multipart {

View File

@ -38,11 +38,11 @@ Multipart::Multipart(const oatpp::String& boundary)
Multipart::Multipart(const Headers& requestHeaders){
auto it = requestHeaders.find("Content-Type");
if(it != requestHeaders.end()) {
auto contentType = requestHeaders.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("Content-Type");
if(contentType) {
oatpp::web::protocol::http::HeaderValueData valueData;
oatpp::web::protocol::http::Parser::parseHeaderValueData(valueData, it->second, ';');
oatpp::web::protocol::http::Parser::parseHeaderValueData(valueData, contentType, ';');
m_boundary = valueData.getTitleParamValue("boundary");

View File

@ -26,16 +26,15 @@
#define oatpp_web_mime_multipart_Multipart_hpp
#include "Part.hpp"
#include <unordered_map>
#include <list>
namespace oatpp { namespace web { namespace mime { namespace multipart {
/**
* Typedef for headers map. Headers map key is case-insensitive.
* `std::unordered_map` of &id:oatpp::data::share::StringKeyLabelCI_FAST; and &id:oatpp::data::share::StringKeyLabel;.
* For more info see &id:oatpp::data::share::LazyStringMap;.
*/
typedef std::unordered_map<oatpp::data::share::StringKeyLabelCI_FAST, oatpp::data::share::StringKeyLabel> Headers;
typedef oatpp::data::share::LazyStringMap<oatpp::data::share::StringKeyLabelCI_FAST> Headers;
/**
* Structure that holds parts of Multipart.

View File

@ -41,11 +41,11 @@ Part::Part(const Headers &headers,
, m_knownSize(knownSize)
{
auto it = m_headers.find("Content-Disposition");
if(it != m_headers.end()) {
auto contentDisposition = m_headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("Content-Disposition");
if(contentDisposition) {
oatpp::web::protocol::http::HeaderValueData valueData;
oatpp::web::protocol::http::Parser::parseHeaderValueData(valueData, it->second, ';');
oatpp::web::protocol::http::Parser::parseHeaderValueData(valueData, contentDisposition, ';');
m_name = valueData.getTitleParamValue("name");
m_filename = valueData.getTitleParamValue("filename");
@ -86,25 +86,16 @@ const Part::Headers& Part::getHeaders() const {
return m_headers;
}
oatpp::String Part::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 Part::getHeader(const oatpp::data::share::StringKeyLabelCI_FAST& headerName) const {
return m_headers.get(headerName);
}
void Part::putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) {
m_headers[key] = value;
m_headers.put(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;
return m_headers.putIfNotExists(key, value);
}
std::shared_ptr<data::stream::InputStream> Part::getInputStream() const {

View File

@ -25,11 +25,9 @@
#ifndef oatpp_web_mime_multipart_Part_hpp
#define oatpp_web_mime_multipart_Part_hpp
#include "oatpp/core/data/share/MemoryLabel.hpp"
#include "oatpp/core/data/share/LazyStringMap.hpp"
#include "oatpp/core/data/stream/Stream.hpp"
#include <unordered_map>
namespace oatpp { namespace web { namespace mime { namespace multipart {
/**
@ -39,9 +37,9 @@ class Part {
public:
/**
* Typedef for headers map. Headers map key is case-insensitive.
* `std::unordered_map` of &id:oatpp::data::share::StringKeyLabelCI_FAST; and &id:oatpp::data::share::StringKeyLabel;.
* For more info see &id:oatpp::data::share::LazyStringMap;.
*/
typedef std::unordered_map<oatpp::data::share::StringKeyLabelCI_FAST, oatpp::data::share::StringKeyLabel> Headers;
typedef oatpp::data::share::LazyStringMap<oatpp::data::share::StringKeyLabelCI_FAST> Headers;
private:
oatpp::String m_name;
oatpp::String m_filename;

View File

@ -26,7 +26,7 @@
#define oatpp_web_mime_multipart_StatefulParser_hpp
#include "oatpp/core/data/stream/ChunkedBuffer.hpp"
#include "oatpp/core/data/share/MemoryLabel.hpp"
#include "oatpp/core/data/share/LazyStringMap.hpp"
#include "oatpp/core/Types.hpp"
#include <unordered_map>
@ -49,9 +49,9 @@ private:
private:
/**
* Typedef for headers map. Headers map key is case-insensitive.
* `std::unordered_map` of &id:oatpp::data::share::StringKeyLabelCI_FAST; and &id:oatpp::data::share::StringKeyLabel;.
* For more info see &id:oatpp::data::share::LazyStringMap;.
*/
typedef std::unordered_map<oatpp::data::share::StringKeyLabelCI_FAST, oatpp::data::share::StringKeyLabel> Headers;
typedef oatpp::data::share::LazyStringMap<oatpp::data::share::StringKeyLabelCI_FAST> Headers;
public:
/**
@ -60,10 +60,10 @@ public:
class Listener {
public:
/**
* Convenience typedef for headers map. Headers map key is case-insensitive.
* `std::unordered_map` of &id:oatpp::data::share::StringKeyLabelCI_FAST; and &id:oatpp::data::share::StringKeyLabel;.
* Typedef for headers map. Headers map key is case-insensitive.
* For more info see &id:oatpp::data::share::LazyStringMap;.
*/
typedef std::unordered_map<oatpp::data::share::StringKeyLabelCI_FAST, oatpp::data::share::StringKeyLabel> Headers;
typedef oatpp::data::share::LazyStringMap<oatpp::data::share::StringKeyLabelCI_FAST> Headers;
public:
/**
@ -97,10 +97,10 @@ public:
class AsyncListener {
public:
/**
* Convenience typedef for headers map. Headers map key is case-insensitive.
* `std::unordered_map` of &id:oatpp::data::share::StringKeyLabelCI_FAST; and &id:oatpp::data::share::StringKeyLabel;.
* Typedef for headers map. Headers map key is case-insensitive.
* For more info see &id:oatpp::data::share::LazyStringMap;.
*/
typedef std::unordered_map<oatpp::data::share::StringKeyLabelCI_FAST, oatpp::data::share::StringKeyLabel> Headers;
typedef oatpp::data::share::LazyStringMap<oatpp::data::share::StringKeyLabelCI_FAST> Headers;
public:
/**

View File

@ -346,7 +346,7 @@ void Parser::parseOneHeader(Headers& headers,
caret.skipChar(' ');
v_int32 valuePos0 = caret.getPosition();
caret.findRN();
headers[name] = oatpp::data::share::StringKeyLabel(headersText, &caret.getData()[valuePos0], caret.getPosition() - valuePos0);
headers.put(name, oatpp::data::share::StringKeyLabel(headersText, &caret.getData()[valuePos0], caret.getPosition() - valuePos0));
caret.skipRN();
} else {
error = Status::CODE_431;
@ -421,8 +421,9 @@ void Parser::parseHeaderValueData(HeaderValueData& data, const oatpp::data::shar
void Utils::writeHeaders(const Headers& headers, data::stream::ConsistentOutputStream* stream) {
auto it = headers.begin();
while(it != headers.end()) {
auto& map = headers.getAll_Unsafe();
auto it = map.begin();
while(it != map.end()) {
stream->write(it->first.getData(), it->first.getSize());
stream->write(": ", 2);
stream->write(it->second.getData(), it->second.getSize());

View File

@ -30,7 +30,7 @@
#include "oatpp/web/protocol/CommunicationError.hpp"
#include "oatpp/core/parser/Caret.hpp"
#include "oatpp/core/data/share/MemoryLabel.hpp"
#include "oatpp/core/data/share/LazyStringMap.hpp"
#include "oatpp/core/collection/ListMap.hpp"
#include "oatpp/core/Types.hpp"
@ -41,15 +41,15 @@ namespace oatpp { namespace web { namespace protocol { namespace http {
/**
* Typedef for headers map. Headers map key is case-insensitive.
* `std::unordered_map` of &id:oatpp::data::share::StringKeyLabelCI_FAST; and &id:oatpp::data::share::StringKeyLabel;.
* For more info see &id:oatpp::data::share::LazyStringMap;.
*/
typedef std::unordered_map<oatpp::data::share::StringKeyLabelCI_FAST, oatpp::data::share::StringKeyLabel> Headers;
typedef oatpp::data::share::LazyStringMap<oatpp::data::share::StringKeyLabelCI_FAST> Headers;
/**
* Typedef for query parameters map.
* `std::unordered_map` of &id:oatpp::data::share::StringKeyLabel; and &id:oatpp::data::share::StringKeyLabel;.
* For more info see &id:oatpp::data::share::LazyStringMap;.
*/
typedef std::unordered_map<oatpp::data::share::StringKeyLabel, oatpp::data::share::StringKeyLabel> QueryParams;
typedef oatpp::data::share::LazyStringMap<oatpp::data::share::StringKeyLabel> QueryParams;
/**
* Http status.
@ -443,7 +443,7 @@ public:
{}
/**
* Get headers map
* Get headers
* @return
*/
const Headers& getHeaders() const {

View File

@ -61,19 +61,14 @@ const http::Headers& Request::getHeaders() const {
const http::QueryParams& Request::getQueryParameters() const {
if(!m_queryParamsParsed) {
m_queryParams = oatpp::network::Url::Parser::labelQueryParams(m_pathVariables.getTail());
oatpp::network::Url::Parser::parseQueryParams(m_queryParams, 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();
}
return getQueryParameters().get(name);
}
oatpp::String Request::getQueryParameter(const oatpp::data::share::StringKeyLabel& name, const oatpp::String& defaultValue) const {
@ -90,24 +85,15 @@ std::shared_ptr<const http::incoming::BodyDecoder> Request::getBodyDecoder() con
}
void Request::putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) {
m_headers[key] = value;
m_headers.put(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;
return m_headers.putIfNotExists(key, value);
}
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;
return m_headers.get(headerName);
}
oatpp::String Request::getPathVariable(const oatpp::data::share::StringKeyLabel& name) const {

View File

@ -28,29 +28,27 @@
namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming {
data::v_io_size RequestHeadersReader::readHeadersSection(data::stream::InputStreamBufferedProxy* stream,
oatpp::data::stream::ConsistentOutputStream* bufferStream,
Result& result) {
data::v_io_size RequestHeadersReader::readHeadersSection(data::stream::InputStreamBufferedProxy* stream, Result& result) {
v_word32 accumulator = 0;
v_int32 progress = 0;
m_bufferStream->setCurrentPosition(0);
data::v_io_size res;
while (true) {
v_int32 desiredToRead = m_buffer.getSize();
if(progress + desiredToRead > m_maxHeadersSize) {
desiredToRead = m_maxHeadersSize - progress;
v_int32 desiredToRead = m_readChunkSize;
if(m_bufferStream->getCurrentPosition() + desiredToRead > m_maxHeadersSize) {
desiredToRead = m_maxHeadersSize - m_bufferStream->getCurrentPosition();
if(desiredToRead <= 0) {
return -1;
}
}
auto bufferData = m_buffer.getData();
m_bufferStream->reserveBytesUpfront(desiredToRead);
auto bufferData = m_bufferStream->getData() + m_bufferStream->getCurrentPosition();
res = stream->peek(bufferData, desiredToRead);
if(res > 0) {
bufferStream->write(bufferData, res);
progress += res;
m_bufferStream->setCurrentPosition(m_bufferStream->getCurrentPosition() + res);
for(v_int32 i = 0; i < res; i ++) {
accumulator <<= 8;
@ -79,17 +77,15 @@ RequestHeadersReader::Result RequestHeadersReader::readHeaders(data::stream::Inp
http::HttpError::Info& error) {
RequestHeadersReader::Result result;
oatpp::data::stream::ChunkedBuffer buffer;
error.ioStatus = readHeadersSection(stream, &buffer, result);
error.ioStatus = readHeadersSection(stream, result);
if(error.ioStatus > 0) {
auto headersText = buffer.toString();
oatpp::parser::Caret caret (headersText);
oatpp::parser::Caret caret (m_bufferStream->getData(), m_bufferStream->getCurrentPosition());
http::Status status;
http::Parser::parseRequestStartingLine(result.startingLine, headersText.getPtr(), caret, status);
http::Parser::parseRequestStartingLine(result.startingLine, nullptr, caret, status);
if(status.code == 0) {
http::Parser::parseHeaders(result.headers, headersText.getPtr(), caret, status);
http::Parser::parseHeaders(result.headers, nullptr, caret, status);
}
}
@ -99,45 +95,42 @@ RequestHeadersReader::Result RequestHeadersReader::readHeaders(data::stream::Inp
oatpp::async::CoroutineStarterForResult<const RequestHeadersReader::Result&>
RequestHeadersReader::readHeadersAsync(const std::shared_ptr<data::stream::InputStreamBufferedProxy>& connection)
RequestHeadersReader::readHeadersAsync(const std::shared_ptr<data::stream::InputStreamBufferedProxy>& stream)
{
class ReaderCoroutine : public oatpp::async::CoroutineWithResult<ReaderCoroutine, const Result&> {
private:
std::shared_ptr<data::stream::InputStreamBufferedProxy> m_stream;
oatpp::data::share::MemoryLabel m_buffer;
v_int32 m_maxHeadersSize;
RequestHeadersReader* m_this;
v_word32 m_accumulator;
v_int32 m_progress;
RequestHeadersReader::Result m_result;
oatpp::data::stream::ChunkedBuffer m_bufferStream;
public:
ReaderCoroutine(const std::shared_ptr<data::stream::InputStreamBufferedProxy>& stream,
const oatpp::data::share::MemoryLabel& buffer, v_int32 maxHeadersSize)
: m_stream(stream)
, m_buffer(buffer)
, m_maxHeadersSize(maxHeadersSize)
ReaderCoroutine(RequestHeadersReader* _this,
const std::shared_ptr<data::stream::InputStreamBufferedProxy>& stream)
: m_this(_this)
, m_stream(stream)
, m_accumulator(0)
, m_progress(0)
{}
{
m_this->m_bufferStream->setCurrentPosition(0);
}
Action act() override {
v_int32 desiredToRead = m_buffer.getSize();
if(m_progress + desiredToRead > m_maxHeadersSize) {
desiredToRead = m_maxHeadersSize - m_progress;
v_int32 desiredToRead = m_this->m_readChunkSize;
if(m_this->m_bufferStream->getCurrentPosition() + desiredToRead > m_this->m_maxHeadersSize) {
desiredToRead = m_this->m_maxHeadersSize - m_this->m_bufferStream->getCurrentPosition();
if(desiredToRead <= 0) {
return error<Error>("[oatpp::web::protocol::http::incoming::RequestHeadersReader::readHeadersAsync()]: Error. Headers section is too large.");
}
}
auto bufferData = m_buffer.getData();
m_this->m_bufferStream->reserveBytesUpfront(desiredToRead);
auto bufferData = m_this->m_bufferStream->getData() + m_this->m_bufferStream->getCurrentPosition();
auto res = m_stream->peek(bufferData, desiredToRead);
if(res > 0) {
m_bufferStream.write(bufferData, res);
m_progress += res;
m_this->m_bufferStream->setCurrentPosition(m_this->m_bufferStream->getCurrentPosition() + res);
for(v_int32 i = 0; i < res; i ++) {
m_accumulator <<= 8;
@ -165,13 +158,12 @@ RequestHeadersReader::readHeadersAsync(const std::shared_ptr<data::stream::Input
}
Action parseHeaders() {
auto headersText = m_bufferStream.toString();
oatpp::parser::Caret caret (headersText);
oatpp::parser::Caret caret (m_this->m_bufferStream->getData(), m_this->m_bufferStream->getCurrentPosition());
http::Status status;
http::Parser::parseRequestStartingLine(m_result.startingLine, headersText.getPtr(), caret, status);
http::Parser::parseRequestStartingLine(m_result.startingLine, nullptr, caret, status);
if(status.code == 0) {
http::Parser::parseHeaders(m_result.headers, headersText.getPtr(), caret, status);
http::Parser::parseHeaders(m_result.headers, nullptr, caret, status);
if(status.code == 0) {
return _return(m_result);
} else {
@ -180,12 +172,12 @@ RequestHeadersReader::readHeadersAsync(const std::shared_ptr<data::stream::Input
} else {
return error<Error>("[oatpp::web::protocol::http::incoming::RequestHeadersReader::readHeadersAsync()]: Error. Can't parse starting line.");
}
}
};
return ReaderCoroutine::startForResult(connection, m_buffer, m_maxHeadersSize);
return ReaderCoroutine::startForResult(this, stream);
}

View File

@ -28,6 +28,7 @@
#include "oatpp/web/protocol/http/Http.hpp"
#include "oatpp/core/async/Coroutine.hpp"
#include "oatpp/core/data/stream/StreamBufferedProxy.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming {
@ -61,21 +62,23 @@ public:
};
private:
data::v_io_size readHeadersSection(data::stream::InputStreamBufferedProxy* stream,
oatpp::data::stream::ConsistentOutputStream* bufferStream,
Result& result);
data::v_io_size readHeadersSection(data::stream::InputStreamBufferedProxy* stream, Result& result);
private:
oatpp::data::share::MemoryLabel m_buffer;
v_int32 m_readChunkSize;
v_int32 m_maxHeadersSize;
oatpp::data::stream::BufferOutputStream* m_bufferStream;
public:
/**
* Constructor.
* @param buffer - buffer to use to read data from stream. &id:oatpp::data::share::MemoryLabel;.
* @param readChunkSize
* @param maxHeadersSize
*/
RequestHeadersReader(const oatpp::data::share::MemoryLabel& buffer, v_int32 maxHeadersSize)
: m_buffer(buffer)
RequestHeadersReader(oatpp::data::stream::BufferOutputStream* bufferStream,
v_int32 readChunkSize = 2048,
v_int32 maxHeadersSize = 4096)
: m_bufferStream(bufferStream)
, m_readChunkSize(readChunkSize)
, m_maxHeadersSize(maxHeadersSize)
{}
@ -92,7 +95,7 @@ public:
* @param stream - `std::shared_ptr` to &id:oatpp::data::stream::InputStreamBufferedProxy;.
* @return - &id:oatpp::async::CoroutineStarterForResult;.
*/
oatpp::async::CoroutineStarterForResult<const RequestHeadersReader::Result&> readHeadersAsync(const std::shared_ptr<data::stream::InputStreamBufferedProxy>& connection);
oatpp::async::CoroutineStarterForResult<const RequestHeadersReader::Result&> readHeadersAsync(const std::shared_ptr<data::stream::InputStreamBufferedProxy>& stream);
};

View File

@ -58,6 +58,10 @@ const http::Headers& Response::getHeaders() const {
return m_headers;
}
oatpp::String Response::getHeader(const oatpp::data::share::StringKeyLabelCI_FAST& headerName) const{
return m_headers.get(headerName);
}
std::shared_ptr<oatpp::data::stream::InputStream> Response::getBodyStream() const {
return m_bodyStream;
}

View File

@ -101,6 +101,13 @@ public:
*/
const http::Headers& getHeaders() const;
/**
* Get header value
* @param headerName - &id:oatpp::data::share::StringKeyLabelCI_FAST;.
* @return - &id:oatpp::String;.
*/
oatpp::String getHeader(const oatpp::data::share::StringKeyLabelCI_FAST& headerName) const;
/**
* Get raw body stream.
* @return - raw body stream as &id:oatpp::data::stream::InputStream;.

View File

@ -88,38 +88,36 @@ void SimpleBodyDecoder::decode(const Headers& headers,
oatpp::data::stream::InputStream* bodyStream,
oatpp::data::stream::WriteCallback* writeCallback) const {
auto transferEncodingIt = headers.find(Header::TRANSFER_ENCODING);
if(transferEncodingIt != headers.end() && transferEncodingIt->second == Header::Value::TRANSFER_ENCODING_CHUNKED) {
auto transferEncoding = headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabelCI_FAST>(Header::TRANSFER_ENCODING);
if(transferEncoding && transferEncoding == Header::Value::TRANSFER_ENCODING_CHUNKED) {
doChunkedDecoding(bodyStream, writeCallback);
} else {
oatpp::data::v_io_size contentLength = 0;
auto contentLengthStrIt = headers.find(Header::CONTENT_LENGTH);
auto contentLengthStr = headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>(Header::CONTENT_LENGTH);
if(!contentLengthStr) {
if(contentLengthStrIt == headers.end()) {
auto connectionStrIt = headers.find(Header::CONNECTION);
if(connectionStrIt != headers.end()) {
auto headerValue = connectionStrIt->second;
if(headerValue.getSize() == 5 && oatpp::base::StrBuffer::equalsCI_FAST(headerValue.getData(), "close", 5)) { // read until connection is closed
oatpp::data::buffer::IOBuffer buffer;
oatpp::data::stream::transfer(bodyStream, writeCallback, 0 /* read until error */, buffer.getData(), buffer.getSize());
} // else - do nothing. invalid response.
}
auto connectionStr = headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabelCI_FAST>(Header::CONNECTION);
if(connectionStr && connectionStr == "close") {
oatpp::data::buffer::IOBuffer buffer;
oatpp::data::stream::transfer(bodyStream, writeCallback, 0 /* read until error */, buffer.getData(), buffer.getSize());
} // else - do nothing. invalid response.
return;
} else {
bool success;
contentLength = oatpp::utils::conversion::strToInt64(contentLengthStrIt->second.toString(), success);
auto contentLength = oatpp::utils::conversion::strToInt64(contentLengthStr.toString(), success);
if(!success){
return; // it is an invalid request/response
}
if(contentLength > 0) {
oatpp::data::buffer::IOBuffer buffer;
oatpp::data::stream::transfer(bodyStream, writeCallback, contentLength, buffer.getData(), buffer.getSize());
}
}
}
@ -225,36 +223,36 @@ oatpp::async::CoroutineStarter SimpleBodyDecoder::doChunkedDecodingAsync(const s
oatpp::async::CoroutineStarter SimpleBodyDecoder::decodeAsync(const Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<oatpp::data::stream::AsyncWriteCallback>& writeCallback) const {
auto transferEncodingIt = headers.find(Header::TRANSFER_ENCODING);
if(transferEncodingIt != headers.end() && transferEncodingIt->second == Header::Value::TRANSFER_ENCODING_CHUNKED) {
auto transferEncoding = headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabelCI_FAST>(Header::TRANSFER_ENCODING);
if(transferEncoding && transferEncoding == Header::Value::TRANSFER_ENCODING_CHUNKED) {
return doChunkedDecodingAsync(bodyStream, writeCallback);
} else {
oatpp::data::v_io_size contentLength = 0;
auto contentLengthStrIt = headers.find(Header::CONTENT_LENGTH);
if(contentLengthStrIt == headers.end()) {
auto connectionStrIt = headers.find(Header::CONNECTION);
if(connectionStrIt != headers.end()) {
auto headerValue = connectionStrIt->second;
auto contentLengthStr = headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>(Header::CONTENT_LENGTH);
if(!contentLengthStr) {
if(headerValue.getSize() == 5 && oatpp::base::StrBuffer::equalsCI_FAST(headerValue.getData(), "close", 5)) { // read until connection is closed
return oatpp::data::stream::transferAsync(bodyStream, writeCallback, 0 /* read until error */, oatpp::data::buffer::IOBuffer::createShared());
}
auto connectionStr = headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabelCI_FAST>(Header::CONNECTION);
if(connectionStr && connectionStr == "close") {
return oatpp::data::stream::transferAsync(bodyStream, writeCallback, 0 /* read until error */, oatpp::data::buffer::IOBuffer::createShared());
}
return nullptr; // else - do nothing. invalid response.
} else {
bool success;
contentLength = oatpp::utils::conversion::strToInt64(contentLengthStrIt->second.toString(), success);
auto contentLength = oatpp::utils::conversion::strToInt64(contentLengthStr.toString(), success);
if(!success){
throw HttpError(http::Status::CODE_400, "Invalid 'Content-Length' Header");
}
if(contentLength > 0) {
return oatpp::data::stream::transferAsync(bodyStream, writeCallback, contentLength, oatpp::data::buffer::IOBuffer::createShared());
} else {
return nullptr;
}
}
}
}

View File

@ -48,7 +48,7 @@ std::shared_ptr<BufferBody> BufferBody::createShared(const oatpp::String& buffer
}
void BufferBody::declareHeaders(Headers& headers) noexcept {
headers[oatpp::web::protocol::http::Header::CONTENT_LENGTH] = oatpp::utils::conversion::int32ToStr(m_buffer->getSize());
headers.put(oatpp::web::protocol::http::Header::CONTENT_LENGTH, oatpp::utils::conversion::int32ToStr(m_buffer->getSize()));
}
void BufferBody::writeToStream(OutputStream* stream) noexcept {

View File

@ -47,7 +47,7 @@ bool ChunkedBody::writeData(OutputStream* stream, const void* data, data::v_io_s
}
void ChunkedBody::declareHeaders(Headers& headers) noexcept {
headers[oatpp::web::protocol::http::Header::TRANSFER_ENCODING] = oatpp::web::protocol::http::Header::Value::TRANSFER_ENCODING_CHUNKED;
headers.put(oatpp::web::protocol::http::Header::TRANSFER_ENCODING, oatpp::web::protocol::http::Header::Value::TRANSFER_ENCODING_CHUNKED);
}

View File

@ -35,7 +35,7 @@ std::shared_ptr<ChunkedBufferBody> ChunkedBufferBody::createShared(const std::sh
}
void ChunkedBufferBody::declareHeaders(Headers& headers) noexcept {
headers[oatpp::web::protocol::http::Header::CONTENT_LENGTH] = oatpp::utils::conversion::int64ToStr(m_buffer->getSize());
headers.put(oatpp::web::protocol::http::Header::CONTENT_LENGTH, oatpp::utils::conversion::int64ToStr(m_buffer->getSize()));
}
void ChunkedBufferBody::writeToStream(OutputStream* stream) noexcept {

View File

@ -34,18 +34,18 @@ bool CommunicationUtils::headerEqualsCI_FAST(const oatpp::data::share::MemoryLab
v_int32 CommunicationUtils::considerConnectionState(const std::shared_ptr<protocol::http::incoming::Request>& request,
const std::shared_ptr<protocol::http::outgoing::Response>& response){
auto outState = response->getHeaders().find(Header::CONNECTION);
if(outState != response->getHeaders().end() && headerEqualsCI_FAST(outState->second, Header::Value::CONNECTION_UPGRADE)) {
auto outState = response->getHeaders().getAsMemoryLabel<oatpp::data::share::StringKeyLabelCI_FAST>(Header::CONNECTION);
if(outState && outState == Header::Value::CONNECTION_UPGRADE) {
return CONNECTION_STATE_UPGRADE;
}
if(request) {
/* Set keep-alive to value specified in the client's request, if no Connection header present in response. */
/* Set keep-alive to value specified in response otherwise */
auto it = request->getHeaders().find(Header::CONNECTION);
if(it != request->getHeaders().end() && headerEqualsCI_FAST(it->second, Header::Value::CONNECTION_KEEP_ALIVE)) {
if(outState != response->getHeaders().end()) {
if(headerEqualsCI_FAST(outState->second, Header::Value::CONNECTION_KEEP_ALIVE)) {
auto connection = request->getHeaders().getAsMemoryLabel<oatpp::data::share::StringKeyLabelCI_FAST>(Header::CONNECTION);
if(connection && connection == Header::Value::CONNECTION_KEEP_ALIVE) {
if(outState) {
if(outState == Header::Value::CONNECTION_KEEP_ALIVE) {
return CONNECTION_STATE_KEEP_ALIVE;
} else {
return CONNECTION_STATE_CLOSE;
@ -60,9 +60,9 @@ v_int32 CommunicationUtils::considerConnectionState(const std::shared_ptr<protoc
/* Set HTTP/1.1 default Connection header value (Keep-Alive), if no Connection header present in response. */
/* Set keep-alive to value specified in response otherwise */
auto& protocol = request->getStartingLine().protocol;
if(protocol.getData() != nullptr && headerEqualsCI_FAST(protocol, "HTTP/1.1")) {
if(outState != response->getHeaders().end()) {
if(headerEqualsCI_FAST(outState->second, Header::Value::CONNECTION_KEEP_ALIVE)) {
if(protocol && headerEqualsCI_FAST(protocol, "HTTP/1.1")) {
if(outState) {
if(outState == Header::Value::CONNECTION_KEEP_ALIVE) {
return CONNECTION_STATE_KEEP_ALIVE;
} else {
return CONNECTION_STATE_CLOSE;
@ -78,8 +78,8 @@ v_int32 CommunicationUtils::considerConnectionState(const std::shared_ptr<protoc
/* If protocol != HTTP/1.1 */
/* Set default Connection header value (Close), if no Connection header present in response. */
/* Set keep-alive to value specified in response otherwise */
if(outState != response->getHeaders().end()) {
if(headerEqualsCI_FAST(outState->second, Header::Value::CONNECTION_KEEP_ALIVE)) {
if(outState) {
if(outState == Header::Value::CONNECTION_KEEP_ALIVE) {
return CONNECTION_STATE_KEEP_ALIVE;
} else {
return CONNECTION_STATE_CLOSE;

View File

@ -43,11 +43,7 @@ void DtoBody::declareHeaders(Headers& headers) noexcept {
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;
}
headers.putIfNotExists(Header::CONTENT_TYPE, m_objectMapper->getInfo().http_content_type);
}
data::v_io_size DtoBody::getKnownSize() {

View File

@ -306,11 +306,11 @@ MultipartBody::MultipartBody(const std::shared_ptr<Multipart>& multipart, data::
void MultipartBody::declareHeaders(Headers& headers) noexcept {
if(m_multipart->getAllParts().empty()) {
headers[oatpp::web::protocol::http::Header::CONTENT_LENGTH] = "0";
headers.put(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();
headers.put(oatpp::web::protocol::http::Header::CONTENT_TYPE, "multipart/form-data; boundary=" + m_multipart->getBoundary());
}
void MultipartBody::writeToStream(OutputStream* stream) noexcept {

View File

@ -30,7 +30,7 @@
#include "oatpp/web/mime/multipart/Multipart.hpp"
#include "oatpp/core/data/stream/BufferInputStream.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing {

View File

@ -23,7 +23,7 @@
***************************************************************************/
#include "Request.hpp"
#include "oatpp/core/data/stream/ChunkedBuffer.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing {
@ -57,16 +57,11 @@ protocol::http::Headers& Request::getHeaders() {
}
void Request::putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) {
m_headers[key] = value;
m_headers.put(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;
return m_headers.putIfNotExists(key, value);
}
std::shared_ptr<Body> Request::getBody() {
@ -78,85 +73,113 @@ void Request::send(data::stream::OutputStream* stream){
if(m_body){
m_body->declareHeaders(m_headers);
} else {
m_headers[Header::CONTENT_LENGTH] = "0";
m_headers.put(Header::CONTENT_LENGTH, "0");
}
stream->write(m_method.getData(), m_method.getSize());
stream->write(" /", 2);
stream->write(m_path.getData(), m_path.getSize());
stream->write(" ", 1);
stream->write("HTTP/1.1", 8);
stream->write("\r\n", 2);
auto it = m_headers.begin();
while(it != m_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 ++;
}
stream->write("\r\n", 2);
oatpp::data::stream::BufferOutputStream buffer;
buffer.write(m_method.getData(), m_method.getSize());
buffer.write(" /", 2);
buffer.write(m_path.getData(), m_path.getSize());
buffer.write(" ", 1);
buffer.write("HTTP/1.1", 8);
buffer.write("\r\n", 2);
http::Utils::writeHeaders(m_headers, &buffer);
buffer.write("\r\n", 2);
if(m_body) {
m_body->writeToStream(stream);
auto bodySize = m_body->getKnownSize();
if(bodySize >= 0 && bodySize + buffer.getCurrentPosition() < buffer.getCapacity()) {
m_body->writeToStream(&buffer);
buffer.flushToStream(stream);
} else {
buffer.flushToStream(stream);
m_body->writeToStream(stream);
}
} else {
buffer.flushToStream(stream);
}
}
oatpp::async::CoroutineStarter Request::sendAsync(const std::shared_ptr<data::stream::OutputStream>& stream){
oatpp::async::CoroutineStarter Request::sendAsync(std::shared_ptr<Request> _this,
const std::shared_ptr<data::stream::OutputStream>& stream)
{
class SendAsyncCoroutine : public oatpp::async::Coroutine<SendAsyncCoroutine> {
private:
std::shared_ptr<Request> m_request;
std::shared_ptr<Request> m_this;
std::shared_ptr<data::stream::OutputStream> m_stream;
std::shared_ptr<oatpp::data::stream::ChunkedBuffer> m_buffer;
std::shared_ptr<oatpp::data::stream::BufferOutputStream> m_headersWriteBuffer;
public:
SendAsyncCoroutine(const std::shared_ptr<Request>& request,
const std::shared_ptr<data::stream::OutputStream>& stream)
: m_request(request)
: m_this(request)
, m_stream(stream)
, m_buffer(oatpp::data::stream::ChunkedBuffer::createShared())
, m_headersWriteBuffer(std::make_shared<oatpp::data::stream::BufferOutputStream>())
{}
Action act() {
if(m_request->m_body){
m_request->m_body->declareHeaders(m_request->m_headers);
if(m_this->m_body){
m_this->m_body->declareHeaders(m_this->m_headers);
} else {
m_request->m_headers[Header::CONTENT_LENGTH] = "0";
m_this->m_headers.put(Header::CONTENT_LENGTH, "0");
}
m_buffer->write(m_request->m_method.getData(), m_request->m_method.getSize());
m_buffer->write(" /", 2);
m_buffer->write(m_request->m_path.getData(), m_request->m_path.getSize());
m_buffer->write(" ", 1);
m_buffer->write("HTTP/1.1", 8);
m_buffer->write("\r\n", 2);
m_headersWriteBuffer->write(m_this->m_method.getData(), m_this->m_method.getSize());
m_headersWriteBuffer->write(" /", 2);
m_headersWriteBuffer->write(m_this->m_path.getData(), m_this->m_path.getSize());
m_headersWriteBuffer->write(" ", 1);
m_headersWriteBuffer->write("HTTP/1.1", 8);
m_headersWriteBuffer->write("\r\n", 2);
http::Utils::writeHeaders(m_request->m_headers, m_buffer.get());
http::Utils::writeHeaders(m_this->m_headers, m_headersWriteBuffer.get());
m_buffer->write("\r\n", 2);
return yieldTo(&SendAsyncCoroutine::writeHeaders);
m_headersWriteBuffer->write("\r\n", 2);
const auto& body = m_this->m_body;
if(body) {
auto bodySize = body->getKnownSize();
if(bodySize >= 0 && bodySize + m_headersWriteBuffer->getCurrentPosition() < m_headersWriteBuffer->getCapacity()) {
return body->writeToStreamAsync(m_headersWriteBuffer)
.next(oatpp::data::stream::BufferOutputStream::flushToStreamAsync(m_headersWriteBuffer, m_stream))
.next(finish());
} else {
return yieldTo(&SendAsyncCoroutine::writeHeaders);
}
} else {
return yieldTo(&SendAsyncCoroutine::writeHeaders);
}
}
Action writeHeaders() {
return m_buffer->flushToStreamAsync(m_stream).next(yieldTo(&SendAsyncCoroutine::writeBody));
return oatpp::data::stream::BufferOutputStream::flushToStreamAsync(m_headersWriteBuffer, m_stream).next(yieldTo(&SendAsyncCoroutine::writeBody));
}
Action writeBody() {
if(m_request->m_body) {
return m_request->m_body->writeToStreamAsync(m_stream).next(finish());
if(m_this->m_body) {
return m_this->m_body->writeToStreamAsync(m_stream).next(finish());
}
return finish();
}
};
return SendAsyncCoroutine::start(shared_from_this(), stream);
return SendAsyncCoroutine::start(_this, stream);
}

View File

@ -33,7 +33,7 @@ namespace oatpp { namespace web { namespace protocol { namespace http { namespac
/**
* Class http::outgoing::Request AKA OutgoingRequest represents client's outgoing request to server.
*/
class Request : public oatpp::base::Countable, public std::enable_shared_from_this<Request> {
class Request : public oatpp::base::Countable {
public:
/**
* Convenience typedef for &id:oatpp::web::protocol::http::Headers;.
@ -124,10 +124,12 @@ public:
/**
* Write request to stream in asynchronous manner.
* @param _this
* @param stream - &id:oatpp::data::stream::OutputStream;.
* @return - &id:oatpp::async::CoroutineStarter;.
*/
oatpp::async::CoroutineStarter sendAsync(const std::shared_ptr<data::stream::OutputStream>& stream);
static oatpp::async::CoroutineStarter sendAsync(std::shared_ptr<Request> _this,
const std::shared_ptr<data::stream::OutputStream>& stream);
};

View File

@ -24,8 +24,6 @@
#include "./Response.hpp"
#include "oatpp/core/data/stream/ChunkedBuffer.hpp"
namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing {
Response::Response(const Status& status,
@ -48,24 +46,15 @@ protocol::http::Headers& Response::getHeaders() {
}
void Response::putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) {
m_headers[key] = value;
m_headers.put(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;
return m_headers.putIfNotExists(key, value);
}
oatpp::String Response::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;
return m_headers.get(headerName);
}
void Response::setConnectionUpgradeHandler(const std::shared_ptr<oatpp::network::server::ConnectionHandler>& handler) {
@ -84,95 +73,94 @@ std::shared_ptr<const Response::ConnectionHandler::ParameterMap> Response::getCo
return m_connectionUpgradeParameters;
}
void Response::send(data::stream::OutputStream* stream) {
void Response::send(data::stream::OutputStream* stream, oatpp::data::stream::BufferOutputStream* headersWriteBuffer) {
if(m_body){
m_body->declareHeaders(m_headers);
} else {
m_headers[Header::CONTENT_LENGTH] = "0";
m_headers.put(Header::CONTENT_LENGTH, "0");
}
oatpp::data::stream::ChunkedBuffer buffer;
headersWriteBuffer->setCurrentPosition(0);
buffer.write("HTTP/1.1 ", 9);
buffer.writeAsString(m_status.code);
buffer.write(" ", 1);
buffer.OutputStream::write(m_status.description);
buffer.write("\r\n", 2);
auto it = m_headers.begin();
while(it != m_headers.end()) {
buffer.write(it->first.getData(), it->first.getSize());
buffer.write(": ", 2);
buffer.write(it->second.getData(), it->second.getSize());
buffer.write("\r\n", 2);
it ++;
}
headersWriteBuffer->write("HTTP/1.1 ", 9);
headersWriteBuffer->writeAsString(m_status.code);
headersWriteBuffer->write(" ", 1);
headersWriteBuffer->OutputStream::write(m_status.description);
headersWriteBuffer->write("\r\n", 2);
buffer.write("\r\n", 2);
http::Utils::writeHeaders(m_headers, headersWriteBuffer);
headersWriteBuffer->write("\r\n", 2);
if(m_body) {
auto bodySize = m_body->getKnownSize();
if(bodySize >= 0 && bodySize + buffer.getSize() < oatpp::data::stream::ChunkedBuffer::CHUNK_ENTRY_SIZE) {
m_body->writeToStream(&buffer);
buffer.flushToStream(stream);
if(bodySize >= 0 && bodySize + headersWriteBuffer->getCurrentPosition() < headersWriteBuffer->getCapacity()) {
m_body->writeToStream(headersWriteBuffer);
headersWriteBuffer->flushToStream(stream);
} else {
buffer.flushToStream(stream);
headersWriteBuffer->flushToStream(stream);
m_body->writeToStream(stream);
}
} else {
buffer.flushToStream(stream);
headersWriteBuffer->flushToStream(stream);
}
}
oatpp::async::CoroutineStarter Response::sendAsync(const std::shared_ptr<data::stream::OutputStream>& stream){
oatpp::async::CoroutineStarter Response::sendAsync(const std::shared_ptr<Response>& _this,
const std::shared_ptr<data::stream::OutputStream>& stream,
const std::shared_ptr<oatpp::data::stream::BufferOutputStream>& headersWriteBuffer)
{
class SendAsyncCoroutine : public oatpp::async::Coroutine<SendAsyncCoroutine> {
private:
std::shared_ptr<Response> m_response;
std::shared_ptr<Response> m_this;
std::shared_ptr<data::stream::OutputStream> m_stream;
std::shared_ptr<oatpp::data::stream::ChunkedBuffer> m_buffer;
std::shared_ptr<oatpp::data::stream::BufferOutputStream> m_headersWriteBuffer;
public:
SendAsyncCoroutine(const std::shared_ptr<Response>& response,
const std::shared_ptr<data::stream::OutputStream>& stream)
: m_response(response)
SendAsyncCoroutine(const std::shared_ptr<Response>& _this,
const std::shared_ptr<data::stream::OutputStream>& stream,
const std::shared_ptr<oatpp::data::stream::BufferOutputStream>& headersWriteBuffer)
: m_this(_this)
, m_stream(stream)
, m_buffer(oatpp::data::stream::ChunkedBuffer::createShared())
, m_headersWriteBuffer(headersWriteBuffer)
{}
Action act() override {
if(m_response->m_body){
m_response->m_body->declareHeaders(m_response->m_headers);
if(m_this->m_body){
m_this->m_body->declareHeaders(m_this->m_headers);
} else {
m_response->m_headers[Header::CONTENT_LENGTH] = "0";
m_this->m_headers.put(Header::CONTENT_LENGTH, "0");
}
m_buffer->write("HTTP/1.1 ", 9);
m_buffer->writeAsString(m_response->m_status.code);
m_buffer->write(" ", 1);
m_buffer->OutputStream::write(m_response->m_status.description);
m_buffer->write("\r\n", 2);
http::Utils::writeHeaders(m_response->m_headers, m_buffer.get());
m_buffer->write("\r\n", 2);
m_headersWriteBuffer->setCurrentPosition(0);
const auto& body = m_response->m_body;
m_headersWriteBuffer->write("HTTP/1.1 ", 9);
m_headersWriteBuffer->writeAsString(m_this->m_status.code);
m_headersWriteBuffer->write(" ", 1);
m_headersWriteBuffer->OutputStream::write(m_this->m_status.description);
m_headersWriteBuffer->write("\r\n", 2);
http::Utils::writeHeaders(m_this->m_headers, m_headersWriteBuffer.get());
m_headersWriteBuffer->write("\r\n", 2);
const auto& body = m_this->m_body;
if(body) {
auto bodySize = body->getKnownSize();
if(bodySize >= 0 && bodySize + m_buffer->getSize() < oatpp::data::stream::ChunkedBuffer::CHUNK_ENTRY_SIZE) {
if(bodySize >= 0 && bodySize + m_headersWriteBuffer->getCurrentPosition() < m_headersWriteBuffer->getCapacity()) {
return body->writeToStreamAsync(m_buffer)
.next(m_buffer->flushToStreamAsync(m_stream))
return body->writeToStreamAsync(m_headersWriteBuffer)
.next(oatpp::data::stream::BufferOutputStream::flushToStreamAsync(m_headersWriteBuffer, m_stream))
.next(finish());
} else {
@ -186,19 +174,19 @@ oatpp::async::CoroutineStarter Response::sendAsync(const std::shared_ptr<data::s
}
Action writeHeaders() {
return m_buffer->flushToStreamAsync(m_stream).next(yieldTo(&SendAsyncCoroutine::writeBody));
return oatpp::data::stream::BufferOutputStream::flushToStreamAsync(m_headersWriteBuffer, m_stream).next(yieldTo(&SendAsyncCoroutine::writeBody));
}
Action writeBody() {
if(m_response->m_body) {
return m_response->m_body->writeToStreamAsync(m_stream).next(finish());
if(m_this->m_body) {
return m_this->m_body->writeToStreamAsync(m_stream).next(finish());
}
return finish();
}
};
return SendAsyncCoroutine::start(shared_from_this(), stream);
return SendAsyncCoroutine::start(_this, stream, headersWriteBuffer);
}

View File

@ -29,13 +29,14 @@
#include "oatpp/web/protocol/http/Http.hpp"
#include "oatpp/network/server/ConnectionHandler.hpp"
#include "oatpp/core/async/Coroutine.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing {
/**
* Class which stores information of outgoing http Response.
*/
class Response : public oatpp::base::Countable, public std::enable_shared_from_this<Response> {
class Response : public oatpp::base::Countable {
public:
/**
* Convenience typedef for Headers. <br>
@ -137,15 +138,20 @@ public:
/**
* Write this Response to stream.
* @param stream - pointer to &id:oatpp::data::stream::OutputStream;.
* @param headersWriteBuffer - pointer to &id:oatpp::data::stream::BufferOutputStream;.
*/
void send(data::stream::OutputStream* stream);
void send(data::stream::OutputStream* stream, oatpp::data::stream::BufferOutputStream* headersWriteBuffer);
/**
* Same as &l:Response::send (); but async.
* @param _this - `this` response.
* @param stream - `std::shared_ptr` to &id:oatpp::data::stream::OutputStream;.
* @param headersWriteBuffer - `std::shared_ptr` to &id:oatpp::data::stream::BufferOutputStream;.
* @return - &id:oatpp::async::CoroutineStarter;.
*/
oatpp::async::CoroutineStarter sendAsync(const std::shared_ptr<data::stream::OutputStream>& stream);
static oatpp::async::CoroutineStarter sendAsync(const std::shared_ptr<Response>& _this,
const std::shared_ptr<data::stream::OutputStream>& stream,
const std::shared_ptr<oatpp::data::stream::BufferOutputStream>& headersWriteBuffer);
};

View File

@ -31,6 +31,12 @@
#include "oatpp/core/concurrency/Thread.hpp"
#include "oatpp/core/data/buffer/IOBuffer.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
#include "oatpp/core/data/stream/StreamBufferedProxy.hpp"
namespace oatpp { namespace web { namespace server {
HttpConnectionHandler::Task::Task(HttpRouter* router,
@ -66,12 +72,16 @@ void HttpConnectionHandler::Task::run(){
v_int32 connectionState = oatpp::web::protocol::http::outgoing::CommunicationUtils::CONNECTION_STATE_CLOSE;
std::shared_ptr<oatpp::web::protocol::http::outgoing::Response> response;
oatpp::data::stream::BufferOutputStream headersInBuffer(2048 /* initial capacity */, 2048 /* grow bytes */);
oatpp::data::stream::BufferOutputStream headersOutBuffer(2048 /* initial capacity */, 2048 /* grow bytes */);
oatpp::web::protocol::http::incoming::RequestHeadersReader headersReader(&headersInBuffer, 2048 /* read chunk size */, 4096 /* max headers size */);
do {
response = HttpProcessor::processRequest(m_router, inStream, m_bodyDecoder, m_errorHandler, m_requestInterceptors, connectionState);
response = HttpProcessor::processRequest(m_router, headersReader, inStream, m_bodyDecoder, m_errorHandler, m_requestInterceptors, connectionState);
if(response) {
response->send(m_connection.get());
response->send(m_connection.get(), &headersOutBuffer);
} else {
return;
}

View File

@ -34,9 +34,6 @@
#include "oatpp/network/server/ConnectionHandler.hpp"
#include "oatpp/network/Connection.hpp"
#include "oatpp/core/data/stream/StreamBufferedProxy.hpp"
#include "oatpp/core/data/buffer/IOBuffer.hpp"
namespace oatpp { namespace web { namespace server {
/**

View File

@ -28,6 +28,7 @@ namespace oatpp { namespace web { namespace server {
std::shared_ptr<protocol::http::outgoing::Response>
HttpProcessor::processRequest(HttpRouter* router,
RequestHeadersReader& headersReader,
const std::shared_ptr<oatpp::data::stream::InputStreamBufferedProxy>& inStream,
const std::shared_ptr<const oatpp::web::protocol::http::incoming::BodyDecoder>& bodyDecoder,
const std::shared_ptr<handler::ErrorHandler>& errorHandler,
@ -35,16 +36,9 @@ HttpProcessor::processRequest(HttpRouter* router,
v_int32& connectionState) {
RequestHeadersReader::Result headersReadResult;
oatpp::web::protocol::http::HttpError::Info error;
{
const v_int32 bufferSize = 2048;
v_char8 buffer [bufferSize];
oatpp::data::share::MemoryLabel bufferLabel(nullptr, buffer, bufferSize);
RequestHeadersReader headersReader(bufferLabel, 4096);
headersReadResult = headersReader.readHeaders(inStream.get(), error);
}
oatpp::web::protocol::http::HttpError::Info error;
auto headersReadResult = headersReader.readHeaders(inStream.get(), error);
if(error.status.code != 0) {
connectionState = oatpp::web::protocol::http::outgoing::CommunicationUtils::CONNECTION_STATE_CLOSE;
@ -130,8 +124,7 @@ oatpp::async::Action HttpProcessor::Coroutine::onHeadersParsed(const RequestHead
}
HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::act() {
RequestHeadersReader headersReader(m_headerReaderBuffer, 4096);
return headersReader.readHeadersAsync(m_inStream).callbackTo(&HttpProcessor::Coroutine::onHeadersParsed);
return m_headersReader.readHeadersAsync(m_inStream).callbackTo(&HttpProcessor::Coroutine::onHeadersParsed);
}
HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::onRequestFormed() {
@ -147,7 +140,8 @@ HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::onResponseFormed() {
m_currentResponse->putHeaderIfNotExists(protocol::http::Header::SERVER, protocol::http::Header::Value::SERVER);
m_connectionState = oatpp::web::protocol::http::outgoing::CommunicationUtils::considerConnectionState(m_currentRequest, m_currentResponse);
return m_currentResponse->sendAsync(m_connection).next(yieldTo(&HttpProcessor::Coroutine::onRequestDone));
return protocol::http::outgoing::Response::sendAsync(m_currentResponse, m_connection, m_headersOutBuffer)
.next(yieldTo(&HttpProcessor::Coroutine::onRequestDone));
}

View File

@ -67,6 +67,9 @@ public:
class Coroutine : public oatpp::async::Coroutine<HttpProcessor::Coroutine> {
private:
HttpRouter* m_router;
oatpp::data::stream::BufferOutputStream m_headersInBuffer;
RequestHeadersReader m_headersReader;
std::shared_ptr<oatpp::data::stream::BufferOutputStream> m_headersOutBuffer;
std::shared_ptr<const oatpp::web::protocol::http::incoming::BodyDecoder> m_bodyDecoder;
std::shared_ptr<handler::ErrorHandler> m_errorHandler;
RequestInterceptors* m_requestInterceptors;
@ -74,7 +77,6 @@ public:
std::shared_ptr<oatpp::data::stream::InputStreamBufferedProxy> m_inStream;
v_int32 m_connectionState;
private:
oatpp::data::share::MemoryLabel m_headerReaderBuffer;
oatpp::web::server::HttpRouter::BranchRouter::Route m_currentRoute;
std::shared_ptr<protocol::http::incoming::Request> m_currentRequest;
std::shared_ptr<protocol::http::outgoing::Response> m_currentResponse;
@ -87,13 +89,15 @@ public:
const std::shared_ptr<oatpp::data::stream::IOStream>& connection,
const std::shared_ptr<oatpp::data::stream::InputStreamBufferedProxy>& inStream)
: m_router(router)
, m_headersInBuffer(2048 /* initialCapacity */, 2048 /* growBytes */)
, m_headersReader(&m_headersInBuffer, 2048 /* read chunk size */, 4096 /* max headers size */)
, m_headersOutBuffer(std::make_shared<oatpp::data::stream::BufferOutputStream>(2048 /* initialCapacity */, 2048 /* growBytes */))
, m_bodyDecoder(bodyDecoder)
, m_errorHandler(errorHandler)
, m_requestInterceptors(requestInterceptors)
, m_connection(connection)
, m_inStream(inStream)
, m_connectionState(oatpp::web::protocol::http::outgoing::CommunicationUtils::CONNECTION_STATE_KEEP_ALIVE)
, m_headerReaderBuffer(oatpp::base::StrBuffer::createShared(2048))
{}
Action act() override;
@ -113,6 +117,7 @@ public:
static std::shared_ptr<protocol::http::outgoing::Response>
processRequest(HttpRouter* router,
RequestHeadersReader& headersReader,
const std::shared_ptr<oatpp::data::stream::InputStreamBufferedProxy>& inStream,
const std::shared_ptr<const oatpp::web::protocol::http::incoming::BodyDecoder>& bodyDecoder,
const std::shared_ptr<handler::ErrorHandler>& errorHandler,

View File

@ -42,7 +42,7 @@ void AuthorizationHandler::renderAuthenticateHeaderValue(ChunkedBuffer& stream)
void AuthorizationHandler::addErrorResponseHeaders(Headers& headers) {
ChunkedBuffer stream;
renderAuthenticateHeaderValue(stream);
headers[protocol::http::Header::WWW_AUTHENTICATE] = stream.toString();
headers.put(protocol::http::Header::WWW_AUTHENTICATE, stream.toString());
}
oatpp::String AuthorizationHandler::getScheme() {

View File

@ -48,7 +48,7 @@ DefaultErrorHandler::handleError(const oatpp::web::protocol::http::Status &statu
response->putHeader(protocol::http::Header::SERVER, protocol::http::Header::Value::SERVER);
response->putHeader(protocol::http::Header::CONNECTION, protocol::http::Header::Value::CONNECTION_CLOSE);
for(auto& pair : headers) {
for(const auto& pair : headers.getAll_Unsafe()) {
response->putHeader(pair.first, pair.second);
}

View File

@ -17,8 +17,12 @@ add_executable(oatppAllTests
oatpp/core/base/memory/PerfTest.hpp
oatpp/core/data/mapping/type/TypeTest.cpp
oatpp/core/data/mapping/type/TypeTest.hpp
oatpp/core/data/share/LazyStringMapTest.cpp
oatpp/core/data/share/LazyStringMapTest.hpp
oatpp/core/data/share/MemoryLabelTest.cpp
oatpp/core/data/share/MemoryLabelTest.hpp
oatpp/core/data/stream/BufferStreamTest.cpp
oatpp/core/data/stream/BufferStreamTest.hpp
oatpp/core/data/stream/ChunkedBufferTest.cpp
oatpp/core/data/stream/ChunkedBufferTest.hpp
oatpp/core/parser/CaretTest.cpp

View File

@ -16,7 +16,9 @@
#include "oatpp/network/virtual_/InterfaceTest.hpp"
#include "oatpp/network/UrlTest.hpp"
#include "oatpp/core/data/stream/BufferStreamTest.hpp"
#include "oatpp/core/data/stream/ChunkedBufferTest.hpp"
#include "oatpp/core/data/share/LazyStringMapTest.hpp"
#include "oatpp/core/data/share/MemoryLabelTest.hpp"
#include "oatpp/core/base/StrBufferTest.hpp"
@ -68,7 +70,12 @@ void runTests() {
OATPP_RUN_TEST(oatpp::test::collection::LinkedListTest);
OATPP_RUN_TEST(oatpp::test::core::data::share::MemoryLabelTest);
OATPP_RUN_TEST(oatpp::test::core::data::share::LazyStringMapTest);
OATPP_RUN_TEST(oatpp::test::core::data::stream::ChunkedBufferTest);
OATPP_RUN_TEST(oatpp::test::core::data::stream::BufferStreamTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::TypeTest);
OATPP_RUN_TEST(oatpp::test::async::LockTest);

View File

@ -0,0 +1,171 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* 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 "LazyStringMapTest.hpp"
#include "oatpp/core/data/share/LazyStringMap.hpp"
namespace oatpp { namespace test { namespace core { namespace data { namespace share {
namespace {
typedef oatpp::data::share::StringKeyLabel StringKeyLabel;
typedef oatpp::data::share::StringKeyLabelCI StringKeyLabelCI;
template<class T>
using LazyStringMap = oatpp::data::share::LazyStringMap<T>;
}
void LazyStringMapTest::onRun() {
p_char8 text = (p_char8) "Hello World!";
{
LazyStringMap<StringKeyLabel> map;
map.put("key1", StringKeyLabel(nullptr, text, 5));
map.put("key2", StringKeyLabel(nullptr, text + 6, 6));
oatpp::String s1 = map.get("key1");
oatpp::String s2 = map.get("key2");
OATPP_ASSERT(s1 == "Hello");
OATPP_ASSERT(s2 == "World!");
oatpp::String s12 = map.get("key1");
oatpp::String s22 = map.get("key2");
OATPP_ASSERT(s1.get() == s12.get());
OATPP_ASSERT(s2.get() == s22.get());
OATPP_ASSERT(map.get("KEY1") == nullptr);
OATPP_ASSERT(map.get("KEY2") == nullptr);
auto all = map.getAll();
auto s13 = all["key1"];
auto s23 = all["key2"];
OATPP_ASSERT(s13.getData() == s1->getData() && s13.getSize() == s1->getSize());
OATPP_ASSERT(s23.getData() == s2->getData() && s23.getSize() == s2->getSize());
OATPP_ASSERT(s1.get() == s13.getMemoryHandle().get());
OATPP_ASSERT(s2.get() == s23.getMemoryHandle().get());
OATPP_ASSERT(map.getSize() == 2);
}
{
LazyStringMap<StringKeyLabelCI> map;
map.put("key1", StringKeyLabel(nullptr, text, 5));
map.put("key2", StringKeyLabel(nullptr, text + 6, 6));
auto s01 = map.getAsMemoryLabel_Unsafe<StringKeyLabel>("key1");
auto s02 = map.getAsMemoryLabel_Unsafe<StringKeyLabel>("key2");
OATPP_ASSERT(s01 == "Hello");
OATPP_ASSERT(s02 == "World!");
OATPP_ASSERT(s01.getMemoryHandle() == nullptr);
OATPP_ASSERT(s02.getMemoryHandle() == nullptr);
auto s1 = map.getAsMemoryLabel<StringKeyLabel>("key1");
auto s2 = map.getAsMemoryLabel<StringKeyLabel>("key2");
OATPP_ASSERT(s1 == "Hello");
OATPP_ASSERT(s2 == "World!");
oatpp::String s12 = map.get("key1");
oatpp::String s22 = map.get("key2");
OATPP_ASSERT(s1.getMemoryHandle().get() == s12.get());
OATPP_ASSERT(s2.getMemoryHandle().get() == s22.get());
OATPP_ASSERT(map.getAsMemoryLabel<StringKeyLabel>("KEY1") == s1);
OATPP_ASSERT(map.getAsMemoryLabel<StringKeyLabel>("KEY2") == s2);
}
{
LazyStringMap<StringKeyLabelCI> map1;
LazyStringMap<StringKeyLabelCI> map2;
map1.put("key1", StringKeyLabel(nullptr, text, 5));
map1.put("key2", StringKeyLabel(nullptr, text + 6, 6));
OATPP_ASSERT(map1.getSize() == 2);
OATPP_ASSERT(map2.getSize() == 0);
map2 = std::move(map1);
OATPP_ASSERT(map1.getSize() == 0);
OATPP_ASSERT(map2.getSize() == 2);
{
auto all = map2.getAll_Unsafe();
auto s1 = all["key1"];
auto s2 = all["key2"];
OATPP_ASSERT(s1.getMemoryHandle() == nullptr);
OATPP_ASSERT(s2.getMemoryHandle() == nullptr);
OATPP_ASSERT(s1 == "Hello");
OATPP_ASSERT(s2 == "World!");
}
{
auto all = map2.getAll();
auto s1 = all["key1"];
auto s2 = all["key2"];
OATPP_ASSERT(s1.getMemoryHandle());
OATPP_ASSERT(s2.getMemoryHandle());
OATPP_ASSERT(s1 == "Hello");
OATPP_ASSERT(s2 == "World!");
auto s12 = map2.get("key1");
auto s22 = map2.get("key2");
OATPP_ASSERT(s1.getMemoryHandle().get() == s12.get());
OATPP_ASSERT(s2.getMemoryHandle().get() == s22.get());
}
}
}
}}}}}

View File

@ -0,0 +1,42 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* 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_share_LazyStringMapTest_hpp
#define oatpp_test_core_data_share_LazyStringMapTest_hpp
#include "oatpp-test/UnitTest.hpp"
namespace oatpp { namespace test { namespace core { namespace data { namespace share {
class LazyStringMapTest : public UnitTest{
public:
LazyStringMapTest():UnitTest("TEST[core::data::share::LazyStringMapTest]"){}
void onRun() override;
};
}}}}}
#endif // oatpp_test_core_data_share_LazyStringMapTest_hpp

View File

@ -127,30 +127,30 @@ void MemoryLabelTest::onRun() {
oatpp::web::protocol::http::Parser::parseHeaders(headers, headersText.getPtr(), caret, status);
OATPP_ASSERT(status.code == 0);
OATPP_ASSERT(headers.size() == 10);
OATPP_ASSERT(headers.getSize() == 10);
OATPP_ASSERT(headers["header0"].equals("value0", 6));
OATPP_ASSERT(headers["header1"].equals("value1", 6));
OATPP_ASSERT(headers["header2"].equals("value2", 6));
OATPP_ASSERT(headers["header3"].equals("value3", 6));
OATPP_ASSERT(headers["header4"].equals("value4", 6));
OATPP_ASSERT(headers["header5"].equals("value5", 6));
OATPP_ASSERT(headers["header6"].equals("value6", 6));
OATPP_ASSERT(headers["header7"].equals("value7", 6));
OATPP_ASSERT(headers["header8"].equals("value8", 6));
OATPP_ASSERT(headers["header9"].equals("value9", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header0").equals("value0", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header1").equals("value1", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header2").equals("value2", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header3").equals("value3", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header4").equals("value4", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header5").equals("value5", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header6").equals("value6", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header7").equals("value7", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header8").equals("value8", 6));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header9").equals("value9", 6));
OATPP_ASSERT(headers["header0"].equals("value0"));
OATPP_ASSERT(headers["header1"].equals("value1"));
OATPP_ASSERT(headers["header2"].equals("value2"));
OATPP_ASSERT(headers["header3"].equals("value3"));
OATPP_ASSERT(headers["header4"].equals("value4"));
OATPP_ASSERT(headers["header5"].equals("value5"));
OATPP_ASSERT(headers["header6"].equals("value6"));
OATPP_ASSERT(headers["header7"].equals("value7"));
OATPP_ASSERT(headers["header8"].equals("value8"));
OATPP_ASSERT(headers["header9"].equals("value9"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header0").equals("value0"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header1").equals("value1"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header2").equals("value2"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header3").equals("value3"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header4").equals("value4"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header5").equals("value5"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header6").equals("value6"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header7").equals("value7"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header8").equals("value8"));
OATPP_ASSERT(headers.getAsMemoryLabel<oatpp::data::share::StringKeyLabel>("header9").equals("value9"));
}

View File

@ -0,0 +1,152 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* 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 "BufferStreamTest.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
#include "oatpp/core/utils/ConversionUtils.hpp"
namespace oatpp { namespace test { namespace core { namespace data { namespace stream {
void BufferStreamTest::onRun() {
typedef oatpp::data::stream::BufferOutputStream BufferOutputStream;
{
BufferOutputStream stream;
stream << "int=" << 1 << ", float=" << 1.1 << ", "
<< "bool=" << true << " or " << false;
OATPP_LOGV(TAG, "str='%s'", stream.toString()->c_str());
stream.setCurrentPosition(0);
stream << 101;
OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(101));
stream.setCurrentPosition(0);
stream << (v_float32)101.1;
OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::float32ToStr(101.1));
stream.setCurrentPosition(0);
stream << (v_float64)101.1;
OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::float64ToStr(101.1));
stream.setCurrentPosition(0);
stream << true;
OATPP_ASSERT(stream.toString() == "true");
stream.setCurrentPosition(0);
stream << false;
OATPP_ASSERT(stream.toString() == "false");
stream.setCurrentPosition(0);
stream << oatpp::String("oat++");
OATPP_ASSERT(stream.toString() == "oat++");
stream.setCurrentPosition(0);
stream << oatpp::Int8(8);
OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(8));
stream.setCurrentPosition(0);
stream << oatpp::Int16(16);
OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(16));
stream.setCurrentPosition(0);
stream << oatpp::Int32(32);
OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(32));
stream.setCurrentPosition(0);
stream << oatpp::Int64(64);
OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(64));
stream.setCurrentPosition(0);
stream << oatpp::Float32(0.32);
OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::float32ToStr(0.32));
stream.setCurrentPosition(0);
stream << oatpp::Float64(0.64);
OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::float64ToStr(0.64));
stream.setCurrentPosition(0);
stream << oatpp::Boolean(true);
OATPP_ASSERT(stream.toString() == "true");
stream.setCurrentPosition(0);
stream << oatpp::Boolean(false);
OATPP_ASSERT(stream.toString() == "false");
}
{
BufferOutputStream stream;
v_int32 fragmentsCount = 1024 * 10;
for(v_int32 i = 0; i < fragmentsCount; i++) {
stream.write("0123456789", 10);
}
auto wholeText = stream.toString();
OATPP_ASSERT(wholeText->getSize() == fragmentsCount * 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));
}
}
{
oatpp::String sample = "0123456789";
oatpp::String text = "";
for(v_int32 i = 0; i < 1024; i++ ) {
text = text + sample;
}
for(v_int32 incStep = 1; incStep <= 1024; incStep ++) {
BufferOutputStream stream(0, incStep);
for(v_int32 i = 0; i < 1024; i++ ) {
stream << sample;
OATPP_ASSERT(stream.getCapacity() >= stream.getCurrentPosition());
}
OATPP_ASSERT(text == stream.toString());
OATPP_ASSERT(stream.getCapacity() < 1024 * (10 + 1));
}
}
}
}}}}}

View File

@ -0,0 +1,43 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* 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_BufferStream_hpp
#define oatpp_test_core_data_stream_BufferStream_hpp
#include "oatpp-test/UnitTest.hpp"
namespace oatpp { namespace test { namespace core { namespace data { namespace stream {
class BufferStreamTest : public UnitTest{
public:
BufferStreamTest():UnitTest("TEST[core::data::stream::BufferStreamTest]"){}
void onRun() override;
};
}}}}}
#endif // oatpp_test_core_data_stream_BufferStream_hpp

View File

@ -44,9 +44,9 @@ void UrlTest::onRun() {
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");
OATPP_ASSERT(url.queryParams.getSize() == 2);
OATPP_ASSERT(url.queryParams.get("q1") == "1");
OATPP_ASSERT(url.queryParams.get("q2") == "2");
}
{
@ -59,9 +59,9 @@ void UrlTest::onRun() {
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");
OATPP_ASSERT(url.queryParams.getSize() == 2);
OATPP_ASSERT(url.queryParams.get("q1") == "1");
OATPP_ASSERT(url.queryParams.get("q2") == "2");
}
{
@ -74,9 +74,9 @@ void UrlTest::onRun() {
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");
OATPP_ASSERT(url.queryParams.getSize() == 2);
OATPP_ASSERT(url.queryParams.get("q1") == "1");
OATPP_ASSERT(url.queryParams.get("q2") == "2");
}
{
@ -89,7 +89,7 @@ void UrlTest::onRun() {
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);
OATPP_ASSERT(url.queryParams.getSize() == 0);
}
{
@ -102,7 +102,7 @@ void UrlTest::onRun() {
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);
OATPP_ASSERT(url.queryParams.getSize() == 0);
}
{
@ -115,67 +115,67 @@ void UrlTest::onRun() {
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);
OATPP_ASSERT(url.queryParams.getSize() == 0);
}
{
const char* urlText = "?key1=value1&key2=value2&key3=value3";
OATPP_LOGV(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");
OATPP_ASSERT(params.getSize() == 3);
OATPP_ASSERT(params.get("key1") == "value1");
OATPP_ASSERT(params.get("key2") == "value2");
OATPP_ASSERT(params.get("key2") == "value2");
}
{
const char *urlText = "?key1=value1&key2&key3=value3";
OATPP_LOGV(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");
OATPP_ASSERT(params.getSize() == 3);
OATPP_ASSERT(params.get("key1") == "value1");
OATPP_ASSERT(params.get("key2") == "");
OATPP_ASSERT(params.get("key3") == "value3");
}
{
const char *urlText = "?key1=value1&key2&key3";
OATPP_LOGV(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"] == "");
OATPP_ASSERT(params.getSize() == 3);
OATPP_ASSERT(params.get("key1") == "value1");
OATPP_ASSERT(params.get("key2") == "");
OATPP_ASSERT(params.get("key3") == "");
}
{
const char *urlText = "label?key1=value1&key2=value2&key3=value3";
OATPP_LOGV(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");
auto params = Url::Parser::parseQueryParams(urlText);
OATPP_ASSERT(params.getSize() == 3);
OATPP_ASSERT(params.get("key1") == "value1");
OATPP_ASSERT(params.get("key2") == "value2");
OATPP_ASSERT(params.get("key2") == "value2");
}
{
const char* urlText = "label?key1=value1&key2&key3=value3";
OATPP_LOGV(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");
auto params = Url::Parser::parseQueryParams(urlText);
OATPP_ASSERT(params.getSize() == 3);
OATPP_ASSERT(params.get("key1") == "value1");
OATPP_ASSERT(params.get("key2") == "");
OATPP_ASSERT(params.get("key3") == "value3");
}
{
const char* urlText = "label?key1=value1&key2&key3";
OATPP_LOGV(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"] == "");
auto params = Url::Parser::parseQueryParams(urlText);
OATPP_ASSERT(params.getSize() == 3);
OATPP_ASSERT(params.get("key1") == "value1");
OATPP_ASSERT(params.get("key2") == "");
OATPP_ASSERT(params.get("key3") == "");
}
}

View File

@ -175,29 +175,29 @@ void FullTest::onRun() {
OATPP_ASSERT(response->getStatusCode() == 200);
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Ping");
auto header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "*");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "GET, POST, OPTIONS");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization");
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "*");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "GET, POST, OPTIONS");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization");
}
{ // test simple OPTIONS with CORS
auto response = client->optionsCors(connection);
OATPP_ASSERT(response->getStatusCode() == 204);
auto header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "*");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "GET, POST, OPTIONS");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization");
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "*");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "GET, POST, OPTIONS");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization");
}
{ // test simple GET with CORS
@ -205,15 +205,15 @@ void FullTest::onRun() {
OATPP_ASSERT(response->getStatusCode() == 200);
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Pong");
auto header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "127.0.0.1");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "GET, POST, OPTIONS");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization");
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "127.0.0.1");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "GET, POST, OPTIONS");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization");
}
{ // test simple GET with CORS
@ -221,15 +221,15 @@ void FullTest::onRun() {
OATPP_ASSERT(response->getStatusCode() == 200);
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Ping");
auto header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "127.0.0.1");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "GET, OPTIONS");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization");
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "127.0.0.1");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "GET, OPTIONS");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization");
}
{ // test simple GET with CORS
@ -237,15 +237,15 @@ void FullTest::onRun() {
OATPP_ASSERT(response->getStatusCode() == 200);
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Pong");
auto header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "127.0.0.1");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "GET, OPTIONS");
header = response->getHeaders().find(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "X-PWNT");
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "127.0.0.1");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "GET, OPTIONS");
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "X-PWNT");
}
{ // test GET with path parameter
@ -324,9 +324,9 @@ void FullTest::onRun() {
"description=Unauthorized\n"
"message=Authorization Required\n");
// should also add the WWW-Authenticate header when Authorization is missing
auto header = response->getHeaders().find(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "Basic realm=\"default-test-realm\"");
auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "Basic realm=\"default-test-realm\"");
}
{ // test custom authorization handler with custom authorization object
@ -343,9 +343,9 @@ void FullTest::onRun() {
"description=Unauthorized\n"
"message=Authorization Required\n");
// should also add the WWW-Authenticate header when Authorization is missing
auto header = response->getHeaders().find(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() == "Basic realm=\"custom-test-realm\"");
auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "Basic realm=\"custom-test-realm\"");
}
{ // test custom authorization handler with custom authorization object with unknown credentials where the
@ -358,9 +358,9 @@ void FullTest::onRun() {
"description=Unauthorized\n"
"message=Unauthorized\n");
// should also add the WWW-Authenticate header when Authorization is missing or wrong
auto header = response->getHeaders().find(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString()->startsWith("Basic realm=\"custom-test-realm\""));
auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header);
OATPP_ASSERT(header->startsWith("Basic realm=\"custom-test-realm\""));
}
{ // test custom authorization handler with custom authorization method
@ -381,9 +381,9 @@ void FullTest::onRun() {
"description=Unauthorized\n"
"message=Unauthorized\n");
// should also add the WWW-Authenticate header when Authorization is missing or wrong
auto header = response->getHeaders().find(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header != response->getHeaders().end());
OATPP_ASSERT(header->second.toString() = "Bearer realm=\"custom-bearer-realm\"");
auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header);
OATPP_ASSERT(header == "Bearer realm=\"custom-bearer-realm\"");
}
{ // test Chunked body

View File

@ -38,7 +38,7 @@
#include "oatpp/network/virtual_/server/ConnectionProvider.hpp"
#include "oatpp/network/virtual_/Interface.hpp"
#include "oatpp/core/data/stream/BufferInputStream.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
#include "oatpp/core/macro/component.hpp"
#include "oatpp-test/web/ClientServerTestRunner.hpp"

View File

@ -38,7 +38,7 @@
#include "oatpp/network/virtual_/server/ConnectionProvider.hpp"
#include "oatpp/network/virtual_/Interface.hpp"
#include "oatpp/core/data/stream/BufferInputStream.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
#include "oatpp/core/macro/component.hpp"
#include "oatpp-test/web/ClientServerTestRunner.hpp"

View File

@ -105,7 +105,7 @@ public:
QUERIES(QueryParams, queries)) {
auto dto = TestDto::createShared();
dto->testMap = dto->testMap->createShared();
for(auto& it : queries) {
for(auto& it : queries.getAll()) {
dto->testMap->put(it.first.toString(), it.second.toString());
}
return createDtoResponse(Status::CODE_200, dto);

View File

@ -27,7 +27,7 @@
#include "oatpp/web/mime/multipart/InMemoryPartReader.hpp"
#include "oatpp/web/mime/multipart/Reader.hpp"
#include "oatpp/core/data/stream/BufferInputStream.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
#include <unordered_map>

View File

@ -88,6 +88,7 @@ void ApiControllerTest::onRun() {
typedef oatpp::web::protocol::http::Status Status;
Controller controller(nullptr);
oatpp::data::stream::BufferOutputStream headersOutBuffer;
{
auto endpoint = controller.Z__ENDPOINT_root;
@ -106,7 +107,7 @@ void ApiControllerTest::onRun() {
OATPP_ASSERT(response->getStatus().code == 200);
oatpp::data::stream::ChunkedBuffer stream;
response->send(&stream);
response->send(&stream, &headersOutBuffer);
OATPP_LOGD(TAG, "response:\n---\n%s\n---\n", stream.toString()->c_str());
@ -133,7 +134,7 @@ void ApiControllerTest::onRun() {
OATPP_ASSERT(response->getStatus().code == 200);
oatpp::data::stream::ChunkedBuffer stream;
response->send(&stream);
response->send(&stream, &headersOutBuffer);
OATPP_LOGD(TAG, "response:\n---\n%s\n---\n", stream.toString()->c_str());
@ -154,7 +155,7 @@ void ApiControllerTest::onRun() {
OATPP_ASSERT(response->getStatus().code == 200);
oatpp::data::stream::ChunkedBuffer stream;
response->send(&stream);
response->send(&stream, &headersOutBuffer);
OATPP_LOGD(TAG, "response:\n---\n%s\n---\n", stream.toString()->c_str());