Skip to content

Commit

Permalink
[websockets] Encode charge point identifier in URL
Browse files Browse the repository at this point in the history
  • Loading branch information
c-jimenez committed Mar 12, 2024
1 parent 6dceb3a commit 3a90533
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 70 deletions.
5 changes: 3 additions & 2 deletions src/chargepoint/ChargePoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
#include "TimerPool.h"
#include "TransactionManager.h"
#include "TriggerMessageManager.h"
#include "Url.h"
#include "Version.h"
#include "WebsocketFactory.h"
#include "WorkerThreadPool.h"
Expand Down Expand Up @@ -1142,7 +1143,7 @@ bool ChargePoint::doConnect()
{
connection_url += "/";
}
connection_url += m_stack_config.chargePointIdentifier();
connection_url += ocpp::websockets::Url::encode(m_stack_config.chargePointIdentifier());

// Check if URL has changed since last connection
std::string last_url;
Expand All @@ -1166,7 +1167,7 @@ bool ChargePoint::doConnect()
{
auto authentication_key = ocpp::helpers::fromHexString(authorization_key);
credentials.user = m_stack_config.chargePointIdentifier();
credentials.password = std::string(reinterpret_cast<const char*>(authentication_key.data()), authorization_key.size());
credentials.password = std::string(reinterpret_cast<const char*>(authentication_key.data()), authentication_key.size());
credentials.password.resize(authentication_key.size());
}
if (security_profile != 1)
Expand Down
3 changes: 2 additions & 1 deletion src/localcontroller/centralsystem/CentralSystemProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.

#include "CentralSystemProxy.h"
#include "ILocalControllerConfig.h"
#include "Url.h"
#include "WebsocketFactory.h"

#include <sstream>
Expand Down Expand Up @@ -86,7 +87,7 @@ bool CentralSystemProxy::connect(const std::string&
{
full_url << "/";
}
full_url << m_identifier;
full_url << ocpp::websockets::Url::encode(m_identifier);

// Connect
ret = m_rpc.start(full_url.str(), credentials, connect_timeout, retry_interval, ping_interval);
Expand Down
62 changes: 28 additions & 34 deletions src/websockets/Url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ Url::Url(const std::string& url)

// Convert path
m_path = match[10].str();
if (!m_path.empty())
{
m_path = encode(m_path);
}

// Convert port
std::string sport = match[9].str();
Expand All @@ -70,55 +66,53 @@ Url::Url(const std::string& url)
m_is_valid = false;
}
}

// Rebuild URL
if (m_is_valid)
{
std::stringstream encoded_url;
encoded_url << m_protocol << "://";
if (!m_username.empty() || !m_password.empty())
{
encoded_url << m_username;
if (!m_password.empty())
{
encoded_url << ":" << m_password;
}
encoded_url << "@";
}
encoded_url << m_address;
if (m_port != 0)
{
encoded_url << ":" << m_port;
}
encoded_url << m_path;
m_url = encoded_url.str();
}
}
}

/** @brief Destructor */
Url::~Url() { }

/** @brief Encode an URL */
std::string Url::encode(const std::string& url) const
/** @brief Encode a part of an URL using RFC3986 percent encoding */
std::string Url::encode(const std::string& url)
{
// RFC3986 : Un reserved chars which must not be encoded
static const char unreserved_char[] = {'-', '_', '.', '~'};

std::stringstream encoded_url;
encoded_url << std::hex;
encoded_url << std::uppercase << std::hex;

for (const auto& c : url)
{
// Safe characters
if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '/'))
// RFC3986 : Only alphanumeric and unreserved chars may be used
// unencoded within a URL
bool encode = true;
if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')))
{
// No encoding
encoded_url << c;
encode = false;
}
else
{
for (size_t i = 0; i < sizeof(unreserved_char) / sizeof(char); i++)
{
if (c == unreserved_char[i])
{
encode = false;
break;
}
}
}

if (encode)
{
// Percent encoding
encoded_url << '%';
encoded_url << std::setw(2) << std::setfill('0') << static_cast<int>(c);
}
else
{
// No encoding
encoded_url << c;
}
}

return encoded_url.str();
Expand Down
6 changes: 3 additions & 3 deletions src/websockets/Url.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ class Url
*/
const std::string& path() const { return m_path; }

/** @brief Encode a part of an URL using RFC3986 percent encoding */
static std::string encode(const std::string& url);

private:
/** @brief Full URL */
std::string m_url;
Expand All @@ -113,9 +116,6 @@ class Url
unsigned int m_port;
/** @brief Path part of the URL */
std::string m_path;

/** @brief Encode an URL */
std::string encode(const std::string& url) const;
};

} // namespace websockets
Expand Down
36 changes: 6 additions & 30 deletions tests/websockets/test_websockets_url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,6 @@ TEST_SUITE("Nominal - hostname as string")
CHECK_EQ(url.path(), "/paf/pouf/");
}

TEST_CASE("URL with port and encoded path")
{
Url url("ftp://pif.com:12345/paf [ pouf / + BIM_bam) = boum ] 10.11.12.13!");

CHECK(url.isValid());
CHECK_EQ(url.url(),
R"(ftp://pif.com:12345/paf%20%5b%20pouf%20/%20%20%2b%20BIM%5fbam%29%20%3d%20boum%20%5d%2010%2e11%2e12%2e13%21)");
CHECK_EQ(url.protocol(), "ftp");
CHECK_EQ(url.username(), "");
CHECK_EQ(url.password(), "");
CHECK_EQ(url.address(), "pif.com");
CHECK_EQ(url.port(), 12345);
CHECK_EQ(url.path(), R"(/paf%20%5b%20pouf%20/%20%20%2b%20BIM%5fbam%29%20%3d%20boum%20%5d%2010%2e11%2e12%2e13%21)");
}

TEST_CASE("URL with username and port")
{
Url url("ftp://[email protected]:12345");
Expand Down Expand Up @@ -228,21 +213,6 @@ TEST_SUITE("Nominal - hostname as IP address")
CHECK_EQ(url.path(), "/paf/pouf/");
}

TEST_CASE("URL with port and encoded path")
{
Url url("ftp://10.189.70.3:12345/paf [ pouf / + BIM_bam) = boum ] 10.11.12.13!");

CHECK(url.isValid());
CHECK_EQ(url.url(),
R"(ftp://10.189.70.3:12345/paf%20%5b%20pouf%20/%20%20%2b%20BIM%5fbam%29%20%3d%20boum%20%5d%2010%2e11%2e12%2e13%21)");
CHECK_EQ(url.protocol(), "ftp");
CHECK_EQ(url.username(), "");
CHECK_EQ(url.password(), "");
CHECK_EQ(url.address(), "10.189.70.3");
CHECK_EQ(url.port(), 12345);
CHECK_EQ(url.path(), R"(/paf%20%5b%20pouf%20/%20%20%2b%20BIM%5fbam%29%20%3d%20boum%20%5d%2010%2e11%2e12%2e13%21)");
}

TEST_CASE("URL with username and port")
{
Url url("ftp://[email protected]:12345");
Expand Down Expand Up @@ -316,6 +286,12 @@ TEST_SUITE("Nominal - hostname as IP address")
CHECK_EQ(url1.port(), url2.port());
CHECK_EQ(url1.path(), url2.path());
}

TEST_CASE("URL percent encoding")
{
std::string url("paf [ pouf / + BIM_bam) = boum ] 10.11.12.13!");
CHECK_EQ(Url::encode(url), R"(paf%20%5B%20pouf%20%2F%20%20%2B%20BIM_bam%29%20%3D%20boum%20%5D%2010.11.12.13%21)");
}
}

TEST_SUITE("Errors")
Expand Down

0 comments on commit 3a90533

Please sign in to comment.