diff --git a/boost/network/uri/normalize.hpp b/boost/network/uri/normalize.hpp new file mode 100644 index 000000000..b83d1ea0f --- /dev/null +++ b/boost/network/uri/normalize.hpp @@ -0,0 +1,82 @@ +// Copyright Fredrik Olofsson 2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef __CPPNETLIB_NETWORK_URI_NORMALIZE__ +#define __CPPNETLIB_NETWORK_URI_NORMALIZE__ + +#pragma once + +#include + +namespace boost +{ + namespace network + { + namespace uri + { + /** + * Normalize a given path and returns it. The path will be resolved and any attempt to + * point to a file above (www) root will be removed. The returned string will allways + * start with a slash ("/"). The path must be an instance of std::basic_string<>. The + * function does handle wide characters as well, so both std::string and std::wstring + * are accepted. Examples: + * + * "/test/test/../" : -> "/test" + * "../../../" : -> "/" + */ + template + inline std::basic_string normalize(std::basic_string path) + { + //why pass by value? See http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ + + typedef std::basic_string StringType; + + //so the method can handle wide characters as well, otherwise must we use L"" or "" depending on char/wchar_t. + static StringType slash1(1, '/'); + static StringType slash2(2, '/'); + static StringType dot2(2, '.'); + static StringType dot2_slash1(dot2 + slash1); + + if(path.empty() || path.front() != '/') + path.insert(0, slash1); + + std::size_t //query_offset = path.find(question), + temp = 0, + pos = 0, + counter = 0; + + while((pos = path.find(slash2)) != StringType::npos) // && pos < query_offset) + path.replace(pos,2,slash1); + + + while((pos = path.find(dot2_slash1)) != StringType::npos)// && pos < query_offset) + { + temp = pos; + while(0 < temp && counter < 2) + { + if(path[--temp] == '/') + ++counter; + } + path.replace(temp, pos-temp+3,slash1); + counter = 0; + } + + pos = /*((query_offset == StringType::npos) ? */ path.size() /*: query_offset)*/ - 1; + if(path[pos] == '/' && pos != 0) + path.erase(pos,1); + + return path; + } + + //A simple helper method, deduce const wchar_t/char * to std::basic_string + template + inline std::basic_string normalize(const Type* path) + { + return normalize(std::basic_string(path)); + } + } + } +} + +#endif \ No newline at end of file diff --git a/libs/network/test/uri/uri_test.cpp b/libs/network/test/uri/uri_test.cpp index 0ee158079..452786df4 100644 --- a/libs/network/test/uri/uri_test.cpp +++ b/libs/network/test/uri/uri_test.cpp @@ -1,4 +1,5 @@ -// Copyright 2009, 2010, 2011 Dean Michael Berris, Jeroen Habraken, Glyn Matthews. +// Copyright 2009, 2010, 2011 Dean Michael Berris, Jeroen Habraken, Glyn Matthews +// Copyright 2012 Fredrik Olofsson // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt of copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -463,3 +465,19 @@ BOOST_AUTO_TEST_CASE(issue_104_test) { instance.reset(); BOOST_CHECK_EQUAL(uri::scheme(copy), "http"); } + +BOOST_AUTO_TEST_CASE(normalize_empty_string) { + BOOST_CHECK_EQUAL(uri::normalize(""), "/"); +} + +BOOST_AUTO_TEST_CASE(normalize_backslash_string) { + BOOST_CHECK_EQUAL(uri::normalize("../../../"), "/"); +} + +BOOST_AUTO_TEST_CASE(normalize_relative_string) { + BOOST_CHECK_EQUAL(uri::normalize("/test/test/test/../test2"), "/test/test/test2"); +} + +BOOST_AUTO_TEST_CASE(normalize_slashend_string) { + BOOST_CHECK_EQUAL(uri::normalize("/test/"), "/test"); +} \ No newline at end of file