Skip to content

Commit 8ea4218

Browse files
authored
Merge pull request #179 from c-jimenez/fix/url_encoding
[websockets] Encode URL when they contains non-ascii or special chars
2 parents f474c39 + dc4c638 commit 8ea4218

File tree

3 files changed

+111
-10
lines changed

3 files changed

+111
-10
lines changed

src/websockets/Url.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
1818

1919
#include "Url.h"
2020

21+
#include <iomanip>
2122
#include <regex>
23+
#include <sstream>
2224

2325
namespace ocpp
2426
{
@@ -46,9 +48,9 @@ Url::Url(const std::string& url)
4648

4749
// Convert path
4850
m_path = match[10].str();
49-
if (m_path.empty())
51+
if (!m_path.empty())
5052
{
51-
m_path = "/";
53+
m_path = encode(m_path);
5254
}
5355

5456
// Convert port
@@ -68,11 +70,59 @@ Url::Url(const std::string& url)
6870
m_is_valid = false;
6971
}
7072
}
73+
74+
// Rebuild URL
75+
if (m_is_valid)
76+
{
77+
std::stringstream encoded_url;
78+
encoded_url << m_protocol << "://";
79+
if (!m_username.empty() || !m_password.empty())
80+
{
81+
encoded_url << m_username;
82+
if (!m_password.empty())
83+
{
84+
encoded_url << ":" << m_password;
85+
}
86+
encoded_url << "@";
87+
}
88+
encoded_url << m_address;
89+
if (m_port != 0)
90+
{
91+
encoded_url << ":" << m_port;
92+
}
93+
encoded_url << m_path;
94+
m_url = encoded_url.str();
95+
}
7196
}
7297
}
7398

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

102+
/** @brief Encode an URL */
103+
std::string Url::encode(const std::string& url) const
104+
{
105+
std::stringstream encoded_url;
106+
encoded_url << std::hex;
107+
108+
for (const auto& c : url)
109+
{
110+
// Safe characters
111+
if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '/'))
112+
{
113+
// No encoding
114+
encoded_url << c;
115+
}
116+
else
117+
{
118+
// Percent encoding
119+
encoded_url << '%';
120+
encoded_url << std::setw(2) << std::setfill('0') << static_cast<int>(c);
121+
}
122+
}
123+
124+
return encoded_url.str();
125+
}
126+
77127
} // namespace websockets
78128
} // namespace ocpp

src/websockets/Url.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ class Url
113113
unsigned int m_port;
114114
/** @brief Path part of the URL */
115115
std::string m_path;
116+
117+
/** @brief Encode an URL */
118+
std::string encode(const std::string& url) const;
116119
};
117120

118121
} // namespace websockets

tests/websockets/test_websockets_url.cpp

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,21 @@ TEST_SUITE("Nominal - hostname as string")
2929
Url url("ftp://pif.com");
3030

3131
CHECK(url.isValid());
32+
CHECK_EQ(url.url(), "ftp://pif.com");
3233
CHECK_EQ(url.protocol(), "ftp");
3334
CHECK_EQ(url.username(), "");
3435
CHECK_EQ(url.password(), "");
3536
CHECK_EQ(url.address(), "pif.com");
3637
CHECK_EQ(url.port(), 0);
37-
CHECK_EQ(url.path(), "/");
38+
CHECK_EQ(url.path(), "");
3839
}
3940

4041
TEST_CASE("Short URL with port")
4142
{
4243
Url url("ftp://pif.com:12345/");
4344

4445
CHECK(url.isValid());
46+
CHECK_EQ(url.url(), "ftp://pif.com:12345/");
4547
CHECK_EQ(url.protocol(), "ftp");
4648
CHECK_EQ(url.username(), "");
4749
CHECK_EQ(url.password(), "");
@@ -50,11 +52,12 @@ TEST_SUITE("Nominal - hostname as string")
5052
CHECK_EQ(url.path(), "/");
5153
}
5254

53-
TEST_CASE("URL wth path")
55+
TEST_CASE("URL with path")
5456
{
5557
Url url("ftp://pif.com/paf/pouf");
5658

5759
CHECK(url.isValid());
60+
CHECK_EQ(url.url(), "ftp://pif.com/paf/pouf");
5861
CHECK_EQ(url.protocol(), "ftp");
5962
CHECK_EQ(url.username(), "");
6063
CHECK_EQ(url.password(), "");
@@ -68,6 +71,7 @@ TEST_SUITE("Nominal - hostname as string")
6871
Url url("ftp://pif.com:12345/paf/pouf/");
6972

7073
CHECK(url.isValid());
74+
CHECK_EQ(url.url(), "ftp://pif.com:12345/paf/pouf/");
7175
CHECK_EQ(url.protocol(), "ftp");
7276
CHECK_EQ(url.username(), "");
7377
CHECK_EQ(url.password(), "");
@@ -76,37 +80,55 @@ TEST_SUITE("Nominal - hostname as string")
7680
CHECK_EQ(url.path(), "/paf/pouf/");
7781
}
7882

83+
TEST_CASE("URL with port and encoded path")
84+
{
85+
Url url("ftp://pif.com:12345/paf [ pouf / + BIM_bam) = boum ] 10.11.12.13!");
86+
87+
CHECK(url.isValid());
88+
CHECK_EQ(url.url(),
89+
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)");
90+
CHECK_EQ(url.protocol(), "ftp");
91+
CHECK_EQ(url.username(), "");
92+
CHECK_EQ(url.password(), "");
93+
CHECK_EQ(url.address(), "pif.com");
94+
CHECK_EQ(url.port(), 12345);
95+
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)");
96+
}
97+
7998
TEST_CASE("URL with username and port")
8099
{
81100
Url url("ftp://[email protected]:12345");
82101

83102
CHECK(url.isValid());
103+
CHECK_EQ(url.url(), "ftp://[email protected]:12345");
84104
CHECK_EQ(url.protocol(), "ftp");
85105
CHECK_EQ(url.username(), "yip76-84");
86106
CHECK_EQ(url.password(), "");
87107
CHECK_EQ(url.address(), "pif.com");
88108
CHECK_EQ(url.port(), 12345);
89-
CHECK_EQ(url.path(), "/");
109+
CHECK_EQ(url.path(), "");
90110
}
91111

92112
TEST_CASE("URL with username, password and port")
93113
{
94114
Url url("ftp://yip76-84:£uiU*^gh#@pif.com:12345");
95115

96116
CHECK(url.isValid());
117+
CHECK_EQ(url.url(), "ftp://yip76-84:£uiU*^gh#@pif.com:12345");
97118
CHECK_EQ(url.protocol(), "ftp");
98119
CHECK_EQ(url.username(), "yip76-84");
99120
CHECK_EQ(url.password(), "£uiU*^gh#");
100121
CHECK_EQ(url.address(), "pif.com");
101122
CHECK_EQ(url.port(), 12345);
102-
CHECK_EQ(url.path(), "/");
123+
CHECK_EQ(url.path(), "");
103124
}
104125

105126
TEST_CASE("URL with username, password, port and path")
106127
{
107128
Url url("ftp://yip76-84:£uiU*^gh#@pif.com:12345/paf/pouf/");
108129

109130
CHECK(url.isValid());
131+
CHECK_EQ(url.url(), "ftp://yip76-84:£uiU*^gh#@pif.com:12345/paf/pouf/");
110132
CHECK_EQ(url.protocol(), "ftp");
111133
CHECK_EQ(url.username(), "yip76-84");
112134
CHECK_EQ(url.password(), "£uiU*^gh#");
@@ -121,6 +143,7 @@ TEST_SUITE("Nominal - hostname as string")
121143
Url url2(url1);
122144

123145
CHECK_EQ(url1.isValid(), url2.isValid());
146+
CHECK_EQ(url1.url(), url2.url());
124147
CHECK_EQ(url1.protocol(), url2.protocol());
125148
CHECK_EQ(url1.username(), url2.username());
126149
CHECK_EQ(url1.password(), url2.password());
@@ -137,6 +160,7 @@ TEST_SUITE("Nominal - hostname as string")
137160
url2 = url1;
138161

139162
CHECK_EQ(url1.isValid(), url2.isValid());
163+
CHECK_EQ(url1.url(), url2.url());
140164
CHECK_EQ(url1.protocol(), url2.protocol());
141165
CHECK_EQ(url1.username(), url2.username());
142166
CHECK_EQ(url1.password(), url2.password());
@@ -153,19 +177,21 @@ TEST_SUITE("Nominal - hostname as IP address")
153177
Url url("ftp://10.189.70.3");
154178

155179
CHECK(url.isValid());
180+
CHECK_EQ(url.url(), "ftp://10.189.70.3");
156181
CHECK_EQ(url.protocol(), "ftp");
157182
CHECK_EQ(url.username(), "");
158183
CHECK_EQ(url.password(), "");
159184
CHECK_EQ(url.address(), "10.189.70.3");
160185
CHECK_EQ(url.port(), 0);
161-
CHECK_EQ(url.path(), "/");
186+
CHECK_EQ(url.path(), "");
162187
}
163188

164189
TEST_CASE("Short URL with port")
165190
{
166191
Url url("ftp://10.189.70.3:12345/");
167192

168193
CHECK(url.isValid());
194+
CHECK_EQ(url.url(), "ftp://10.189.70.3:12345/");
169195
CHECK_EQ(url.protocol(), "ftp");
170196
CHECK_EQ(url.username(), "");
171197
CHECK_EQ(url.password(), "");
@@ -174,11 +200,12 @@ TEST_SUITE("Nominal - hostname as IP address")
174200
CHECK_EQ(url.path(), "/");
175201
}
176202

177-
TEST_CASE("URL wth path")
203+
TEST_CASE("URL with path")
178204
{
179205
Url url("ftp://10.189.70.3/paf/pouf");
180206

181207
CHECK(url.isValid());
208+
CHECK_EQ(url.url(), "ftp://10.189.70.3/paf/pouf");
182209
CHECK_EQ(url.protocol(), "ftp");
183210
CHECK_EQ(url.username(), "");
184211
CHECK_EQ(url.password(), "");
@@ -192,6 +219,7 @@ TEST_SUITE("Nominal - hostname as IP address")
192219
Url url("ftp://10.189.70.3:12345/paf/pouf/");
193220

194221
CHECK(url.isValid());
222+
CHECK_EQ(url.url(), "ftp://10.189.70.3:12345/paf/pouf/");
195223
CHECK_EQ(url.protocol(), "ftp");
196224
CHECK_EQ(url.username(), "");
197225
CHECK_EQ(url.password(), "");
@@ -200,37 +228,55 @@ TEST_SUITE("Nominal - hostname as IP address")
200228
CHECK_EQ(url.path(), "/paf/pouf/");
201229
}
202230

231+
TEST_CASE("URL with port and encoded path")
232+
{
233+
Url url("ftp://10.189.70.3:12345/paf [ pouf / + BIM_bam) = boum ] 10.11.12.13!");
234+
235+
CHECK(url.isValid());
236+
CHECK_EQ(url.url(),
237+
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)");
238+
CHECK_EQ(url.protocol(), "ftp");
239+
CHECK_EQ(url.username(), "");
240+
CHECK_EQ(url.password(), "");
241+
CHECK_EQ(url.address(), "10.189.70.3");
242+
CHECK_EQ(url.port(), 12345);
243+
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)");
244+
}
245+
203246
TEST_CASE("URL with username and port")
204247
{
205248
Url url("ftp://[email protected]:12345");
206249

207250
CHECK(url.isValid());
251+
CHECK_EQ(url.url(), "ftp://[email protected]:12345");
208252
CHECK_EQ(url.protocol(), "ftp");
209253
CHECK_EQ(url.username(), "yip76-84");
210254
CHECK_EQ(url.password(), "");
211255
CHECK_EQ(url.address(), "10.189.70.3");
212256
CHECK_EQ(url.port(), 12345);
213-
CHECK_EQ(url.path(), "/");
257+
CHECK_EQ(url.path(), "");
214258
}
215259

216260
TEST_CASE("URL with username, password and port")
217261
{
218262
Url url("ftp://yip76-84:£uiU*^gh#@10.189.70.3:12345");
219263

220264
CHECK(url.isValid());
265+
CHECK_EQ(url.url(), "ftp://yip76-84:£uiU*^gh#@10.189.70.3:12345");
221266
CHECK_EQ(url.protocol(), "ftp");
222267
CHECK_EQ(url.username(), "yip76-84");
223268
CHECK_EQ(url.password(), "£uiU*^gh#");
224269
CHECK_EQ(url.address(), "10.189.70.3");
225270
CHECK_EQ(url.port(), 12345);
226-
CHECK_EQ(url.path(), "/");
271+
CHECK_EQ(url.path(), "");
227272
}
228273

229274
TEST_CASE("URL with username, password, port and path")
230275
{
231276
Url url("ftp://yip76-84:£uiU*^gh#@10.189.70.3:12345/paf/pouf/");
232277

233278
CHECK(url.isValid());
279+
CHECK_EQ(url.url(), "ftp://yip76-84:£uiU*^gh#@10.189.70.3:12345/paf/pouf/");
234280
CHECK_EQ(url.protocol(), "ftp");
235281
CHECK_EQ(url.username(), "yip76-84");
236282
CHECK_EQ(url.password(), "£uiU*^gh#");
@@ -245,6 +291,7 @@ TEST_SUITE("Nominal - hostname as IP address")
245291
Url url2(url1);
246292

247293
CHECK_EQ(url1.isValid(), url2.isValid());
294+
CHECK_EQ(url1.url(), url2.url());
248295
CHECK_EQ(url1.protocol(), url2.protocol());
249296
CHECK_EQ(url1.username(), url2.username());
250297
CHECK_EQ(url1.password(), url2.password());
@@ -261,6 +308,7 @@ TEST_SUITE("Nominal - hostname as IP address")
261308
url2 = url1;
262309

263310
CHECK_EQ(url1.isValid(), url2.isValid());
311+
CHECK_EQ(url1.url(), url2.url());
264312
CHECK_EQ(url1.protocol(), url2.protocol());
265313
CHECK_EQ(url1.username(), url2.username());
266314
CHECK_EQ(url1.password(), url2.password());

0 commit comments

Comments
 (0)