Skip to content

Commit 275ed5d

Browse files
committed
Added a function to normalize the URI path and used it to better test URI equality.
1 parent a127593 commit 275ed5d

File tree

5 files changed

+135
-15
lines changed

5 files changed

+135
-15
lines changed

include/network/uri/normalize.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) Glyn Matthews 2012.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at
4+
// http://www.boost.org/LICENSE_1_0.txt)
5+
6+
7+
#ifndef __BOOST_NETWORK_URI_NORMALIZE_INC__
8+
# define __BOOST_NETWORK_URI_NORMALIZE_INC__
9+
10+
# include <network/uri/uri.hpp>
11+
12+
namespace network {
13+
uri::string_type normalize_path(const uri::const_range_type &path);
14+
15+
//uri normalize(const uri &uri_);
16+
//
17+
//uri::string_type normalize_scheme(const uri &uri_);
18+
//
19+
//uri::string_type normalize_user_info(const uri &uri_);
20+
//
21+
//uri::string_type normalize_host(const uri &uri_);
22+
//
23+
//uri::string_type normalize_port(const uri &uri_);
24+
//
25+
//uri::string_type normalize_path(const uri &uri_);
26+
//
27+
//uri::string_type normalize_fragment(const uri &uri_);
28+
//
29+
//uri::string_type normalize_query(const uri &uri_);
30+
} // namespace network
31+
32+
#endif // __BOOST_NETWORK_URI_NORMALIZE_INC__

libs/network/src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU)
1717
endif()
1818
endif()
1919

20-
set(CPP-NETLIB_URI_SRCS uri/uri.cpp uri/schemes.cpp)
20+
set(CPP-NETLIB_URI_SRCS uri/uri.cpp uri/schemes.cpp uri/normalize.cpp)
2121
add_library(cppnetlib-uri ${CPP-NETLIB_URI_SRCS})
2222
foreach (src_file ${CPP-NETLIB_URI_SRCS})
2323
if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU)

libs/network/src/uri/normalize.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) Glyn Matthews 2012.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at
4+
// http://www.boost.org/LICENSE_1_0.txt)
5+
6+
7+
# include <network/uri/normalize.hpp>
8+
# include <vector>
9+
# include <stack>
10+
# include <boost/algorithm/string/split.hpp>
11+
# include <boost/algorithm/string/join.hpp>
12+
# include <boost/algorithm/string/predicate.hpp>
13+
# include <boost/algorithm/string/classification.hpp>
14+
# include <boost/range/as_literal.hpp>
15+
# include <boost/range/algorithm_ext/erase.hpp>
16+
# include <boost/range/algorithm/for_each.hpp>
17+
18+
namespace network {
19+
uri::string_type normalize_path(const uri::const_range_type &path) {
20+
using namespace boost;
21+
using namespace boost::algorithm;
22+
23+
// add trailing /
24+
if (empty(path)) {
25+
return uri::string_type("/");
26+
}
27+
28+
std::vector<uri::string_type> path_segments;
29+
split(path_segments, path, is_any_of("/"));
30+
31+
// remove single dot segments
32+
remove_erase_if(path_segments, [] (const uri::string_type &s) {
33+
return equal(s, as_literal("."));
34+
});
35+
36+
// remove double dot segments
37+
std::vector<std::string> normalized_segments;
38+
auto depth = 0;
39+
for_each(path_segments, [&normalized_segments, &depth] (const uri::string_type &s) {
40+
assert(depth >= 0);
41+
if (equal(s, as_literal(".."))) {
42+
normalized_segments.pop_back();
43+
}
44+
else {
45+
normalized_segments.push_back(s);
46+
}
47+
});
48+
49+
if (!empty(normalized_segments.back()) &&
50+
!contains(normalized_segments.back(), as_literal("."))) {
51+
normalized_segments.push_back(uri::string_type());
52+
}
53+
54+
return join(normalized_segments, "/");
55+
}
56+
} // namespace network

libs/network/src/uri/uri.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <network/uri/uri.ipp>
88
#include <network/uri/uri.hpp>
9+
#include <network/uri/normalize.hpp>
910
#include <boost/algorithm/string/predicate.hpp>
1011
#include <map>
1112

@@ -46,7 +47,7 @@ bool operator == (const uri &lhs, const uri &rhs) {
4647

4748
if (equal) {
4849
// TODO: test normalized paths
49-
equal = boost::iequals(lhs.path_range(), rhs.path_range());
50+
equal = boost::iequals(normalize_path(lhs.path_range()), normalize_path(rhs.path_range()));
5051
}
5152

5253
if (equal) {

libs/network/test/uri/uri_test.cpp

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -336,19 +336,19 @@ BOOST_AUTO_TEST_CASE(swap_test) {
336336
BOOST_AUTO_TEST_CASE(equality_test) {
337337
network::uri uri_1("http://www.example.com/");
338338
network::uri uri_2("http://www.example.com/");
339-
BOOST_CHECK(uri_1 == uri_2);
339+
BOOST_CHECK_EQUAL(uri_1, uri_2);
340340
}
341341

342342
BOOST_AUTO_TEST_CASE(equality_test_1) {
343343
network::uri uri_1("http://www.example.com/");
344344
std::string uri_2("http://www.example.com/");
345-
BOOST_CHECK(uri_1 == uri_2);
345+
BOOST_CHECK_EQUAL(uri_1, uri_2);
346346
}
347347

348348
BOOST_AUTO_TEST_CASE(equality_test_2) {
349349
std::string uri_1("http://www.example.com/");
350350
network::uri uri_2("http://www.example.com/");
351-
BOOST_CHECK(uri_1 == uri_2);
351+
BOOST_CHECK_EQUAL(uri_1, uri_2);
352352
}
353353

354354
BOOST_AUTO_TEST_CASE(equality_test_3) {
@@ -366,62 +366,93 @@ BOOST_AUTO_TEST_CASE(equality_test_4) {
366366
BOOST_AUTO_TEST_CASE(equality_test_reordered_query) {
367367
network::uri uri_1("http://www.example.com/?a=1&b=2");
368368
network::uri uri_2("http://www.example.com/?b=2&a=1");
369-
BOOST_CHECK(uri_1 == uri_2);
369+
BOOST_CHECK_EQUAL(uri_1, uri_2);
370370
}
371371

372372
BOOST_AUTO_TEST_CASE(equality_test_capitalized_scheme) {
373373
network::uri uri_1("http://www.example.com/");
374374
network::uri uri_2("HTTP://www.example.com/");
375-
BOOST_CHECK(uri_1 == uri_2);
375+
BOOST_CHECK_EQUAL(uri_1, uri_2);
376376
}
377377

378378
BOOST_AUTO_TEST_CASE(equality_test_capitalized_host) {
379379
network::uri uri_1("http://www.example.com/");
380380
network::uri uri_2("http://WWW.EXAMPLE.COM/");
381-
BOOST_CHECK(uri_1 == uri_2);
381+
BOOST_CHECK_EQUAL(uri_1, uri_2);
382382
}
383383

384384
BOOST_AUTO_TEST_CASE(equality_test_user_info) {
385385
network::uri uri_1("ftp://john.doe@ftp.example.com/");
386386
network::uri uri_2("ftp://JOHN.DOE@ftp.example.com/");
387-
BOOST_CHECK(uri_1 != uri_2);
387+
BOOST_CHECK_PREDICATE(std::not_equal_to<network::uri>(), (uri_1)(uri_2));
388388
}
389389

390390
BOOST_AUTO_TEST_CASE(equality_test_default_http_port) {
391391
network::uri uri_1("http://www.example.com/");
392392
network::uri uri_2("http://www.example.com:80/");
393-
BOOST_CHECK(uri_1 == uri_2);
393+
BOOST_CHECK_EQUAL(uri_1, uri_2);
394394
}
395395

396396
BOOST_AUTO_TEST_CASE(equality_test_default_http_port_2) {
397397
network::uri uri_1("http://www.example.com:80/");
398398
network::uri uri_2("http://www.example.com/");
399-
BOOST_CHECK(uri_1 == uri_2);
399+
BOOST_CHECK_EQUAL(uri_1, uri_2);
400400
}
401401

402402
BOOST_AUTO_TEST_CASE(equality_test_default_https_port) {
403403
network::uri uri_1("https://www.example.com/");
404404
network::uri uri_2("https://www.example.com:443/");
405-
BOOST_CHECK(uri_1 == uri_2);
405+
BOOST_CHECK_EQUAL(uri_1, uri_2);
406406
}
407407

408408
BOOST_AUTO_TEST_CASE(equality_test_default_https_port_2) {
409409
network::uri uri_1("https://www.example.com:443/");
410410
network::uri uri_2("https://www.example.com/");
411-
BOOST_CHECK(uri_1 == uri_2);
411+
BOOST_CHECK_EQUAL(uri_1, uri_2);
412+
}
413+
414+
BOOST_AUTO_TEST_CASE(equality_test_empty_path_with_trailing_slash) {
415+
network::uri uri_1("http://www.example.com/");
416+
network::uri uri_2("http://www.example.com");
417+
BOOST_CHECK_EQUAL(uri_1, uri_2);
418+
}
419+
420+
BOOST_AUTO_TEST_CASE(equality_test_with_single_dot_segment) {
421+
network::uri uri_1("http://www.example.com/./path");
422+
network::uri uri_2("http://www.example.com/path");
423+
BOOST_CHECK_EQUAL(uri_1, uri_2);
424+
}
425+
426+
BOOST_AUTO_TEST_CASE(equality_test_with_double_dot_segment) {
427+
network::uri uri_1("http://www.example.com/1/../2/");
428+
network::uri uri_2("http://www.example.com/2/");
429+
BOOST_CHECK_EQUAL(uri_1, uri_2);
430+
}
431+
432+
BOOST_AUTO_TEST_CASE(equality_test_with_trailing_slash) {
433+
network::uri uri_1("http://www.example.com/path/");
434+
network::uri uri_2("http://www.example.com/path");
435+
BOOST_CHECK_EQUAL(uri_1, uri_2);
436+
}
437+
438+
BOOST_AUTO_TEST_CASE(equality_test_with_file_ext) {
439+
network::uri uri_1("http://www.example.com/filename.txt");
440+
network::uri uri_2("http://www.example.com/filename.txt/");
441+
BOOST_CHECK_PREDICATE(std::not_equal_to<network::uri>(), (uri_1)(uri_2));
412442
}
413443

414444
BOOST_AUTO_TEST_CASE(inequality_test) {
415445
network::uri uri_1("http://www.example.com/");
416446
network::uri uri_2("http://www.example.com/");
417-
BOOST_CHECK(!(uri_1 != uri_2));
447+
BOOST_CHECK(!(uri_1 != uri_2));
418448
}
419449

420450
BOOST_AUTO_TEST_CASE(less_than_test) {
421451
// uri_1 is lexicographically less than uri_2
422452
network::uri uri_1("http://www.example.com/");
423453
network::uri uri_2("http://www.example.org/");
424-
BOOST_CHECK(uri_1 < uri_2);
454+
BOOST_CHECK_PREDICATE(std::less<network::uri>(), (uri_1)(uri_2));
455+
//BOOST_CHECK(uri_1 < uri_2);
425456
}
426457

427458
BOOST_AUTO_TEST_CASE(username_test) {

0 commit comments

Comments
 (0)