[DEV] URI is ready

This commit is contained in:
Edouard DUPIN 2018-09-06 21:52:19 +02:00
parent f75cb4e67f
commit 1b64f05c43
12 changed files with 453 additions and 110 deletions

View File

@ -307,6 +307,10 @@ etk::Path etk::Path::getParent() const {
return out;
}
void etk::Path::clear() {
m_data.clear();
}
bool etk::Path::operator== (const etk::Path& _obj) const {
return m_data == _obj.m_data;
}

View File

@ -121,6 +121,10 @@ namespace etk {
* @return Parent path.
*/
etk::Path getParent() const;
/**
* @brief Clear data.
*/
void clear();
/**
* @brief Check if the 2 Path are identical.
* @param[in] _obj Path to compare.

View File

@ -1,41 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/url/Query.hpp>
etk::uri::Query::Querry() {
}
etk::uri::Query::Querry(const etk::String& _value) {
}
void etk::uri::Query::setEncoded(const etk::String& _value) {
}
etk::String etk::uri::Query::getEncoded() const {
return "";
}
void etk::uri::Query::set(const etk::String& _key, const etk::String& _value) {
}
bool etk::uri::Query::exist(const etk::String& _key) {
return false;
}
void etk::uri::Query::erase(const etk::String& _key) {
}
etk::String etk::uri::Query::get(const etk::String& _key) {
return "";
}

150
etk/uri/Query.cpp Normal file
View File

@ -0,0 +1,150 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <etk/uri/Query.hpp>
#include <etk/debug.hpp>
static const etk::String hexData = "0123456789ABCDEF";
static etk::String pourcentEncode(const etk::String& _data) {
etk::String out;
for (auto &it : _data) {
if ( (it >= 'a' && it <= 'z')
|| (it >= 'A' && it <= 'Z')
|| (it >= '0' && it <= '9')
|| it == '-'
|| it == '_'
|| it == '.'
|| it == '~') {
out += it;
} else {
out += "%";
out += hexData[(uint32_t(it)>>4)&0x0F];
out += hexData[uint32_t(it)&0x0F];
}
}
return out;
}
static int32_t convertStringHexToInt(const char _value) {
if (_value >= 'a' && _value <= 'z') {
return int32_t(_value) - int32_t('a') + 10;
}
if (_value >= 'A' && _value <= 'Z') {
return int32_t(_value) - int32_t('A') + 10;
}
if (_value >= '0' && _value <= '9') {
return int32_t(_value) - int32_t('0');
}
TK_ERROR("Not a hexadecimal Value: '" << _value << "'");
return 0;
}
static etk::String pourcentDecode(const etk::String& _data) {
etk::String out;
for (size_t iii=0; iii<_data.size(); ++iii) {
auto it = _data[iii];
if (it == '%') {
if (iii+2 < _data.size()) {
auto val1 = convertStringHexToInt(_data[iii+1])<<4;
val1 += convertStringHexToInt(_data[iii+2]);
out += char(val1);
iii += 2;
} else {
TK_ERROR("can not convert pourcent ==> input size error: '" << _data << "'");
return out;
}
} else {
out += it;
}
}
return out;
}
etk::uri::Query::Query() {
}
etk::uri::Query::Query(const etk::String& _value) {
setEncoded(_value);
}
void etk::uri::Query::setEncoded(const etk::String& _value) {
m_data.clear();
auto listElements = etk::split(_value, '&');
for (auto &it : listElements) {
if (it.size() == 0) {
continue;
}
auto offset = it.find('=');
if (offset == etk::String::npos) {
m_data.set(pourcentDecode(it), "");
continue;
}
m_data.set(pourcentDecode(it.extract(0, offset)),
pourcentDecode(it.extract(offset+1, etk::String::npos)));
}
}
etk::String etk::uri::Query::getEncoded() const {
etk::String out;
for (auto &it: m_data) {
if (out.empty() == false) {
out += "&";
}
out += pourcentEncode(it.first);
if (it.second.empty() == false) {
out += "=";
out += pourcentEncode(it.second);
}
}
return out;
}
etk::String etk::uri::Query::getNotEncoded() const {
etk::String out;
for (auto &it: m_data) {
if (out.empty() == false) {
out += "&";
}
out += it.first;
if (it.second.empty() == false) {
out += "=";
out += it.second;
}
}
return out;
}
void etk::uri::Query::set(const etk::String& _key, const etk::String& _value) {
m_data.set(_key, _value);
}
bool etk::uri::Query::exist(const etk::String& _key) {
return m_data.exist(_key);
}
void etk::uri::Query::erase(const etk::String& _key) {
m_data.erase(_key);
}
etk::String etk::uri::Query::get(const etk::String& _key) {
return m_data[_key];
}
void etk::uri::Query::clear() {
m_data.clear();
}
etk::Stream& etk::operator <<(etk::Stream& _os, const etk::uri::Query& _obj) {
_os << "Query{";
_os << _obj.getNotEncoded();
_os << "}";
return _os;
}
bool etk::uri::Query::isEmpty() const {
return m_data.size() == 0;
}

View File

@ -13,23 +13,23 @@
namespace etk {
namespace uri {
/**
* @brief Querry Interface management.
* @brief query Interface management.
*/
class Query {
private:
etk::Map<etk::String, etk::String> m_query; //!< Querry data
etk::Map<etk::String, etk::String> m_data; //!< query data
public:
ETK_CONSTRUCTOR_MOVE_DEFAULT(Query);
ETK_CONSTRUCTOR_COPY_DEFAULT(Query);
/**
* @brief Default contructor.
*/
Querry();
Query();
/**
* @brief Set with a specific querry string
* @param[in] _value querry data
* @brief Set with a specific query string
* @param[in] _value query data
*/
Querry(const etk::String& _value);
Query(const etk::String& _value);
/**
* @brief Set the encoded query.
* @param[in] _value encoded data.
@ -40,6 +40,11 @@ namespace etk {
* @return encoded data.
*/
etk::String getEncoded() const;
/**
* @brief Get the Not encoded query (for debug only).
* @return encoded data.
*/
etk::String getNotEncoded() const;
/**
* @brief Set an element of the query.
* @param[in] _key Key of the query.
@ -64,7 +69,18 @@ namespace etk {
* @return associated data.
*/
etk::String get(const etk::String& _key);
/**
* @brief clear data
*/
void clear();
/**
* @brief check if the querry is empty
* @return true The querry have no data. false Otherwise
*/
bool isEmpty() const;
};
}
//! @not_in_doc
etk::Stream& operator <<(etk::Stream& _os, const etk::uri::Query& _obj);
}

View File

@ -3,34 +3,10 @@
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
#include <etk/fs/Type.hpp>
#include <etk/String.hpp>
#include <etk/Map.hpp>
#include <etk/uri/Uri.hpp>
#include <etk/debug.hpp>
namespace etk {
/**
* @brief Uniform resource interface manage internal resource and nerwork resource (like URL)
* Format is manage like : __SCHEME__://__USER__:__PASSWORD__@__SERVER__:__PORT__/__PATH__?__QUERY__#__FRAGMENT__
*/
class Uri {
private:
etk::String m_scheme; //!< Sheme of the uri.
etk::String m_user; //!< user name
etk::String m_password; //!< password (crypted/hashed)
etk::String m_server; //!< server name
uint16_t m_port; //!< Port of the server
etk::Path m_path; //!< Path data
etk::uri::Query m_query; //!< querry interface
etk::String m_fragment; //!< fragment data
public:
ETK_CONSTRUCTOR_MOVE_DEFAULT(Uri);
ETK_CONSTRUCTOR_COPY_DEFAULT(Uri);
/**
* @brief Default contructor.
*/
etk::Uri::Uri() {
}
@ -43,14 +19,79 @@ etk::Uri::Uri(const char * _value) {
set(_value);
}
void etk::Uri::set(const etk::String& _value) {
}
void etk::Uri::set(const char * _value) {
set(etk::String(_value));
}
void etk::Uri::clear() {
m_scheme.clear();
m_user.clear();
m_password.clear();
m_server.clear();
m_port = 0;
m_path.clear();
m_query.clear();
m_fragment.clear();
}
void etk::Uri::set(etk::String _value) {
TK_VERBOSE("parse: '" << _value << "'");
size_t pos = _value.find("://");
if (pos != etk::String::npos) {
// find scheme
m_scheme = _value.extract(0, pos);
_value = _value.extract(pos+3, etk::String::npos);
TK_VERBOSE("find scheme : '" << m_scheme << "' ==||== '" << _value << "'");
}
pos = _value.rfind('#');
if (pos != etk::String::npos) {
// find scheme
m_fragment = _value.extract(pos+1, etk::String::npos);
_value = _value.extract(0, pos);
TK_VERBOSE("find fragment: '" << m_fragment << "' ==||== '" << _value << "'");
}
pos = _value.rfind('?');
if (pos != etk::String::npos) {
// find query
m_query.setEncoded(_value.extract(pos+1, etk::String::npos));
_value = _value.extract(0, pos);
TK_VERBOSE("find query: '" << m_query << "' ==||== '" << _value << "'");
}
pos = _value.find('/');
if (pos != etk::String::npos) {
// find path
m_path = _value.extract(pos+1, etk::String::npos);
_value = _value.extract(0, pos);
TK_VERBOSE("find scheme : '" << m_path << "' ==||== '" << _value << "'");
}
pos = _value.find('@');
if (pos != etk::String::npos) {
TK_VERBOSE("find server With name");
// find server with user
etk::String userInfo = _value.extract(0, pos);
size_t pos_2 = userInfo.find(':');
if (pos_2 != etk::String::npos) {
// find password:
m_user = userInfo.extract(0, pos_2);
m_password = userInfo.extract(pos_2+1, etk::String::npos);
} else {
m_user=userInfo;
m_password="";
}
_value = _value.extract(pos+1, etk::String::npos);
TK_VERBOSE("find user / pass : '" << m_user << "' / '" << m_password << "' ==||== '" << _value << "'");
}
pos = _value.find(':');
if (pos != etk::String::npos) {
m_server = _value.extract(0, pos);
m_port = string_to_uint16_t(_value.extract(pos+1, etk::String::npos));
} else {
m_server = _value;
m_port = 0;
}
TK_VERBOSE("find server / port : '" << m_server << "' / '" << m_port << "'");
}
etk::String etk::Uri::get() {
etk::String out;
if (m_scheme != "") {
@ -76,7 +117,7 @@ etk::String etk::Uri::get() {
out += "/";
out += m_path.getString();
}
if(m_query.size() != 0) {
if(m_query.isEmpty() == false) {
out += "?";
out += m_query.getEncoded();
}
@ -84,6 +125,7 @@ etk::String etk::Uri::get() {
out += "#";
out += m_fragment;
}
return out;
}
const etk::String& etk::Uri::getScheme() const {

View File

@ -9,32 +9,10 @@
#include <etk/fs/Type.hpp>
#include <etk/String.hpp>
#include <etk/Map.hpp>
#include <etk/uri/Query.hpp>
#include <etk/fs/Path.hpp>
namespace etk {
class Query {
private:
etk::Map<etk::String, etk::String> m_query; //!< Querry data
public:
ETK_CONSTRUCTOR_MOVE_DEFAULT(Query);
ETK_CONSTRUCTOR_COPY_DEFAULT(Query);
/**
* @brief Default contructor.
*/
Querry();
/**
* @brief Set with a specific querry string
* @param[in] _value querry data
*/
Querry(const etk::String& _value);
void setEncoded(const etk::String& _value);
etk::String getEncoded() const;
void set(const etk::String& _key, const etk::String& _value);
bool exist(const etk::String& _key);
etk::String get(const etk::String& _key);
};
/**
* @brief Uniform resource interface manage internal resource and nerwork resource (like URL)
* Format is manage like : __SCHEME__://__USER__:__PASSWORD__@__SERVER__:__PORT__/__PATH__?__QUERY__#__FRAGMENT__
@ -47,7 +25,7 @@ namespace etk {
etk::String m_server; //!< server name
uint16_t m_port = 0; //!< Port of the server
etk::Path m_path; //!< Path data
etk::uri::Query m_query; //!< querry interface
etk::uri::Query m_query; //!< query interface
etk::String m_fragment; //!< fragment data
public:
ETK_CONSTRUCTOR_MOVE_DEFAULT(Uri);
@ -70,7 +48,7 @@ namespace etk {
* @brief Contructor with basic URI.
* @param[in] _value Element basic URI
*/
void set(const etk::String& _value);
void set(etk::String _value);
/**
* @brief Contructor with basic URI.
* @param[in] _value Element basic URI
@ -142,12 +120,12 @@ namespace etk {
*/
void setPath(const etk::Path& _value);
/**
* @brief Get the Querry.
* @return Querry data.
* @brief Get the query.
* @return query data.
*/
const etk::uri::Query& getQuery() const;
/**
* @brief Set the new querry.
* @brief Set the new query.
* @param[in] _value Data.
*/
void setQuery(const etk::uri::Query& _value);
@ -161,6 +139,10 @@ namespace etk {
* @param[in] _value New fragment
*/
void setFragment(const etk::String& _value);
/**
* @brief Clear the structure.
*/
void clear();
};
}

View File

@ -41,7 +41,7 @@ def configure(target, my_module):
my_module.compile_version("c++", 2017)
# add dependency of the generic C++ library:
my_module.add_depend([
'etk-base',
'etk-core',
'echrono',
'elog',
'cxx'

View File

@ -31,6 +31,8 @@ def configure(target, my_module):
'test/testPath.cpp',
'test/testPermissions.cpp',
'test/testTheme.cpp',
'test/testUri.cpp',
'test/testQuery.cpp',
])
"""
'test/ConstructDestruct.cpp',

View File

@ -57,12 +57,13 @@ def configure(target, my_module):
'etk/os/FSNodeRight.cpp',
'etk/archive/Archive.cpp',
'etk/archive/Zip.cpp',
'etk/uri/Uri.cpp',
'etk/uri/Query.cpp',
])
my_module.add_header_file([
'etk/etk.hpp',
'etk/debug.hpp',
'etk/stdTools.hpp',
'etk/tool.hpp',
'etk/Noise.hpp',
'etk/Color.hpp',
@ -93,6 +94,8 @@ def configure(target, my_module):
'etk/archive/Zip.hpp',
'etk/TreeNode.hpp',
'etk/FlatTree.hpp',
'etk/uri/Uri.hpp',
'etk/uri/Query.hpp',
])
# build in C++ mode
@ -103,7 +106,7 @@ def configure(target, my_module):
'm',
'elog',
'ememory',
'etk-base',
'etk-core',
])
# TODO: Remove this ==> when ready to remove dependency with stl:
my_module.add_depend(['cxx'])

16
test/testQuery.cpp Normal file
View File

@ -0,0 +1,16 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license MPL v2.0 (see license file)
*/
#include <etest/etest.hpp>
#include <test-debug/debug.hpp>
#include <etk/uri/Query.hpp>
TEST(TestQuery, defaultContructor) {
etk::uri::Query query;
EXPECT_EQ(query.getEncoded(), "");
}

165
test/testUri.cpp Normal file
View File

@ -0,0 +1,165 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license MPL v2.0 (see license file)
*/
#include <etest/etest.hpp>
#include <test-debug/debug.hpp>
#include <etk/uri/Uri.hpp>
TEST(TestUri, defaultContructor) {
etk::Uri uri;
EXPECT_EQ(uri.get(), "");
EXPECT_EQ(uri.getScheme(), "");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "");
EXPECT_EQ(uri.getPort(), 0);
EXPECT_EQ(uri.getPath(), etk::Path(""));
EXPECT_EQ(uri.getQuery().getEncoded(), "");
EXPECT_EQ(uri.getFragment(), "");
}
TEST(TestUri, base_1) {
etk::String value = "__SCHEME__://__USER__:__PASSWORD__@__SERVER__:1234/__PATH__?__QUERY__#__FRAGMENT__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "__SCHEME__");
EXPECT_EQ(uri.getUser(), "__USER__");
EXPECT_EQ(uri.getPassword(), "__PASSWORD__");
EXPECT_EQ(uri.getServer(), "__SERVER__");
EXPECT_EQ(uri.getPort(), 1234);
EXPECT_EQ(uri.getPath(), etk::Path("__PATH__"));
EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__");
EXPECT_EQ(uri.getFragment(), "__FRAGMENT__");
}
TEST(TestUri, base_2) {
etk::String value = "__SCHEME__://__USER__@__SERVER__:1234/__PATH__?__QUERY__#__FRAGMENT__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "__SCHEME__");
EXPECT_EQ(uri.getUser(), "__USER__");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "__SERVER__");
EXPECT_EQ(uri.getPort(), 1234);
EXPECT_EQ(uri.getPath(), etk::Path("__PATH__"));
EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__");
EXPECT_EQ(uri.getFragment(), "__FRAGMENT__");
}
TEST(TestUri, base_3) {
etk::String value = "__SCHEME__://__SERVER__:1234/__PATH__?__QUERY__#__FRAGMENT__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "__SCHEME__");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "__SERVER__");
EXPECT_EQ(uri.getPort(), 1234);
EXPECT_EQ(uri.getPath(), etk::Path("__PATH__"));
EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__");
EXPECT_EQ(uri.getFragment(), "__FRAGMENT__");
}
TEST(TestUri, base_4) {
etk::String value = "__SERVER__:1234/__PATH__?__QUERY__#__FRAGMENT__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "__SERVER__");
EXPECT_EQ(uri.getPort(), 1234);
EXPECT_EQ(uri.getPath(), etk::Path("__PATH__"));
EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__");
EXPECT_EQ(uri.getFragment(), "__FRAGMENT__");
}
TEST(TestUri, base_5) {
etk::String value = "__SERVER__/__PATH__?__QUERY__#__FRAGMENT__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "__SERVER__");
EXPECT_EQ(uri.getPort(), 0);
EXPECT_EQ(uri.getPath(), etk::Path("__PATH__"));
EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__");
EXPECT_EQ(uri.getFragment(), "__FRAGMENT__");
}
TEST(TestUri, base_6) {
etk::String value = "__SERVER__/__PATH__?__QUERY__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "__SERVER__");
EXPECT_EQ(uri.getPort(), 0);
EXPECT_EQ(uri.getPath(), etk::Path("__PATH__"));
EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__");
EXPECT_EQ(uri.getFragment(), "");
}
TEST(TestUri, base_7) {
etk::String value = "__SERVER__/__PATH__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "__SERVER__");
EXPECT_EQ(uri.getPort(), 0);
EXPECT_EQ(uri.getPath(), etk::Path("__PATH__"));
EXPECT_EQ(uri.getQuery().getEncoded(), "");
EXPECT_EQ(uri.getFragment(), "");
}
TEST(TestUri, base_8) {
etk::String value = "__SERVER__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "__SERVER__");
EXPECT_EQ(uri.getPort(), 0);
EXPECT_EQ(uri.getPath(), etk::Path(""));
EXPECT_EQ(uri.getQuery().getEncoded(), "");
EXPECT_EQ(uri.getFragment(), "");
}
TEST(TestUri, base_9) {
etk::String value = "__SERVER__:1234";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "__SERVER__");
EXPECT_EQ(uri.getPort(), 1234);
EXPECT_EQ(uri.getPath(), etk::Path(""));
EXPECT_EQ(uri.getQuery().getEncoded(), "");
EXPECT_EQ(uri.getFragment(), "");
}
TEST(TestUri, base_10) {
etk::String value = "__SCHEME__:///__PATH__?__QUERY__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "__SCHEME__");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "");
EXPECT_EQ(uri.getPort(), 0);
EXPECT_EQ(uri.getPath(), etk::Path("__PATH__"));
EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__");
EXPECT_EQ(uri.getFragment(), "");
}