encoding: introduce URL-encoder/decoder

This commit is contained in:
Leonid Stryzhevskyi 2023-01-10 23:20:26 +02:00
parent 66e94ea869
commit ed5efd1bcf
6 changed files with 348 additions and 1 deletions

27
changelog/1.4.0.md Normal file
View File

@ -0,0 +1,27 @@
# Oat++ 1.3.0
Previous release - [1.3.0](1.3.0.md)
Feel free to ask questions - [Chat on Gitter!](https://gitter.im/oatpp-framework/Lobby)
Contents:
- [URL Encoder And Decoder](#url-encoder-and-decoder)
## URL Encoder And Decoder
```cpp
#include "oatpp/encoding/Url.hpp"
...
oatpp::String data = "Hello URL-Encoder!!!";
oatpp::encoding::Url::Config config;
auto encoded = oatpp::encoding::Url::encode(data, config);
auto decoded = oatpp::encoding::Url::decode(encoded);
OATPP_ASSERT(decoded == data);
```
**Note**: Oat++ does NOT automatically decode URL and its parameters on endpoint hit.

123
src/oatpp/encoding/Url.cpp Normal file
View File

@ -0,0 +1,123 @@
/***************************************************************************
*
* 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 "Url.hpp"
#include "oatpp/core/data/stream/BufferStream.hpp"
namespace oatpp { namespace encoding {
Url::Config::Config() {
disallowCharRange(0, 255);
allowCharRange('0', '9');
allowCharRange('a', 'z');
allowCharRange('A', 'Z');
allowChar('-');
allowChar('.');
allowChar('_');
allowChar('~');
}
void Url::Config::allowChar(v_char8 c) {
allowedChars[c] = true;
}
void Url::Config::allowCharRange(v_char8 from, v_char8 to) {
for(v_int32 i = from; i <= to; i++) {
allowedChars[i] = true;
}
}
void Url::Config::disallowChar(v_char8 c) {
allowedChars[c] = false;
}
void Url::Config::disallowCharRange(v_char8 from, v_char8 to) {
for(v_int32 i = from; i <= to; i++) {
allowedChars[i] = false;
}
}
void Url::encode(data::stream::ConsistentOutputStream *stream, const void *data, v_buff_size size, const Config& config) {
p_char8 pdata = (p_char8) data;
for(v_buff_size i = 0; i < size; i++) {
v_char8 c = pdata[i];
if(config.allowedChars[c]) {
stream->writeCharSimple(c);
} else if(c == ' ' && config.spaceToPlus) {
stream->writeCharSimple('+');
} else {
stream->writeCharSimple('%');
Hex::encode(stream, pdata + i, 1, config.hexAlphabet);
}
}
}
void Url::decode(data::stream::ConsistentOutputStream* stream, const void* data, v_buff_size size) {
p_char8 pdata = (p_char8) data;
v_buff_size i = 0;
while (i < size) {
v_char8 c = pdata[i];
if(c == '%') {
if(size - i > 1) {
Hex::decode(stream, pdata + i + 1, 2);
i += 3;
} else {
break;
}
} else if (c == '+') {
stream->writeCharSimple(' ');
i ++;
} else {
stream->writeCharSimple(c);
i ++;
}
}
}
oatpp::String Url::encode(const oatpp::String data, const Config& config) {
data::stream::BufferOutputStream stream(data->size() * 3);
encode(&stream, data->data(), data->size(), config);
return stream.toString();
}
oatpp::String Url::decode(const oatpp::String data) {
data::stream::BufferOutputStream stream(data->size());
decode(&stream, data->data(), data->size());
return stream.toString();
}
}}

View File

@ -0,0 +1,64 @@
/***************************************************************************
*
* 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_encoding_Url_hpp
#define oatpp_encoding_Url_hpp
#include "Hex.hpp"
#include "oatpp/core/data/stream/Stream.hpp"
namespace oatpp { namespace encoding {
class Url {
public:
struct Config {
bool spaceToPlus = false;
const char* hexAlphabet = Hex::ALPHABET_UPPER;
bool allowedChars[256];
Config();
void allowChar(v_char8 c);
void allowCharRange(v_char8 from, v_char8 to);
void disallowChar(v_char8 c);
void disallowCharRange(v_char8 from, v_char8 to);
};
public:
static void encode(data::stream::ConsistentOutputStream* stream, const void* data, v_buff_size size, const Config& config);
static void decode(data::stream::ConsistentOutputStream* stream, const void* data, v_buff_size size);
static oatpp::String encode(const oatpp::String data, const Config& config);
static oatpp::String decode(const oatpp::String data);
};
}}
#endif //oatpp_encoding_Url_hpp

View File

@ -25,8 +25,9 @@
#include "oatpp/parser/json/mapping/BooleanTest.hpp"
#include "oatpp/parser/json/mapping/UnorderedSetTest.hpp"
#include "oatpp/encoding/UnicodeTest.hpp"
#include "oatpp/encoding/Base64Test.hpp"
#include "oatpp/encoding/UnicodeTest.hpp"
#include "oatpp/encoding/UrlTest.hpp"
#include "oatpp/core/parser/CaretTest.hpp"
#include "oatpp/core/provider/PoolTest.hpp"
@ -133,6 +134,7 @@ void runTests() {
OATPP_RUN_TEST(oatpp::test::encoding::Base64Test);
OATPP_RUN_TEST(oatpp::test::encoding::UnicodeTest);
OATPP_RUN_TEST(oatpp::test::encoding::UrlTest);
OATPP_RUN_TEST(oatpp::test::network::UrlTest);
OATPP_RUN_TEST(oatpp::test::network::ConnectionPoolTest);

View File

@ -0,0 +1,90 @@
/***************************************************************************
*
* 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 "UrlTest.hpp"
#include "oatpp/core/utils/Random.hpp"
#include "oatpp/encoding/Url.hpp"
namespace oatpp { namespace test { namespace encoding {
void UrlTest::onRun(){
{
oatpp::encoding::Url::Config config;
config.spaceToPlus = false;
for(v_int32 i = 0; i < 100; i++) {
oatpp::String buff(100);
utils::random::Random::randomBytes((p_char8) buff->data(), buff->size());
auto encoded = oatpp::encoding::Url::encode(buff, config);
auto decoded = oatpp::encoding::Url::decode(encoded);
OATPP_ASSERT(decoded == buff);
}
}
{
oatpp::encoding::Url::Config config;
config.spaceToPlus = true;
for(v_int32 i = 0; i < 100; i++) {
oatpp::String buff(100);
utils::random::Random::randomBytes((p_char8) buff->data(), buff->size());
auto encoded = oatpp::encoding::Url::encode(buff, config);
auto decoded = oatpp::encoding::Url::decode(encoded);
OATPP_ASSERT(decoded == buff);
}
}
{
oatpp::encoding::Url::Config config;
config.spaceToPlus = false;
auto encoded = oatpp::encoding::Url::encode(" ", config);
OATPP_ASSERT(encoded == "%20");
}
{
oatpp::encoding::Url::Config config;
config.spaceToPlus = true;
auto encoded = oatpp::encoding::Url::encode(" ", config);
OATPP_ASSERT(encoded == "+");
}
{
oatpp::encoding::Url::Config config;
config.spaceToPlus = false;
auto encoded = oatpp::encoding::Url::encode("Смачна Овсяночка!", config);
OATPP_ASSERT(encoded == "%D0%A1%D0%BC%D0%B0%D1%87%D0%BD%D0%B0%20%D0%9E%D0%B2%D1%81%D1%8F%D0%BD%D0%BE%D1%87%D0%BA%D0%B0%21");
}
{
oatpp::encoding::Url::Config config;
config.spaceToPlus = true;
auto encoded = oatpp::encoding::Url::encode("Смачна Овсяночка!", config);
OATPP_ASSERT(encoded == "%D0%A1%D0%BC%D0%B0%D1%87%D0%BD%D0%B0+%D0%9E%D0%B2%D1%81%D1%8F%D0%BD%D0%BE%D1%87%D0%BA%D0%B0%21");
}
}
}}}

View File

@ -0,0 +1,41 @@
/***************************************************************************
*
* 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_encoding_UrlTest_hpp
#define oatpp_test_encoding_UrlTest_hpp
#include "oatpp-test/UnitTest.hpp"
namespace oatpp { namespace test { namespace encoding {
class UrlTest : public UnitTest{
public:
UrlTest():UnitTest("TEST[encoding::UrlTest]"){}
void onRun() override;
};
}}}
#endif /* oatpp_test_encoding_UrlTest_hpp */