Skip to content
This repository was archived by the owner on Apr 2, 2020. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions boost/network/uri/normalize.hpp
Original file line number Diff line number Diff line change
@@ -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 <string>

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 <typename Type>
inline std::basic_string<Type> normalize(std::basic_string<Type> path)
{
//why pass by value? See http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're not modifying the parameter, no need to pass by value. There is also no reason why this should be a "regular" function that takes a value and returns a new object. You might as well take the string as a non-cost lvalue reference and modify it in place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it will make calls like: normalize("something") impossible. Why not just create a wrapper function in that case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is exactly the point: you shouldn't allow normalize("something") when you obviously really want to modify a string using your normalization routine. What you should be supporting is:

template <class T> void normalize(basic_string<T> &path);

If anybody wants to use this function, they should do:

std::string path = "./foo";
normalize(path);
assert(path == "foo");

Also, this functionality sounds like it's already in Boost.Filesystem and is very specific to filesystem paths that I'm having a hard time seeing whether it's worth having in cpp-netlib.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I see, in that case so should this pull request be closed, if you are not interested to have it. I just thought it could be a good thing to have in the library, especially when it remove any attempts to receive a directory above "wwwroot". But I came up with another thing, sending files in a effective way. See what I have written about it in "uri thread" on the Google groups thread. You can answer there as well, or maybe Glyn.

PS. I will let Glyn close this pull request, when you have decided if this function should be added or not, but if so, please let me know faster, so I don´t waste time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've replied to that thread. As far as this pull request is concerned I think it's better if you look at whether Boost.Filesystem does what you want to do before you abandon this work. If it doesn't then it might be worth adding this functionality to that library because this is about filesystem paths already and not URIs.

About not wasting time, the best way to avoid this is to let us know what you want to work on and communicate with us how you intend to do it or while you're doing it. Thanks for the effort and I'm looking forward to your other contributions in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been busy, therefore late answer

Well, I currently only use the async_server and the uri class, so anything which make those classes better would I be interested in, specially in async_server implementation. Its robustness, exception safety, the possibility to add more "logging possibilities", performance and so on. Maybe a short web-server example would be a great thing to-do as well, because I already comfortable with async_server impl :-) But in that way, were should I write all questions? Github, google groups?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The best place to let everyone know what you want to work on is the mailing list. There's no other place where the discussions happen but there.

Github issues are reserved for filing bugs. General support and development concerns are discussed in the mailing list (Google groups).

As for the web server example, look at https://github.com/cpp-netlib/cpp-netlib/blob/master/libs/network/example/http/fileserver.cpp which already does practically everything you'd want from a fileserver. If you want to extend that to do other things then be my guest and send a pull request against it.

Let's continue this discussion in the mailing list to get a larger audience involved.


typedef std::basic_string<Type> 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should not be function local statics. If anything you should use the constants type where these values are already defined in a single static location.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must do it when, as fast I just including network/constants.hpp I got some compile errors I cannot solve:

2>C:\cpp-netlib\branch\boost/network/constants.hpp(150): error C2065: 'unsupported_tag' : undeclared identifier
2> C:\cpp-netlib\branch\boost/network/constants.hpp(153) : see reference to class template instantiation 'boost::network::constants' being compiled
2>C:\cpp-netlib\branch\boost/network/constants.hpp(150): error C2974: 'boost::mpl::if_' : invalid template argument for 'T3', type expected
2> C:\boost\include\boost/mpl/if.hpp(56) : see declaration of 'boost::mpl::if_'
2>C:\cpp-netlib\branch\boost/network/constants.hpp(151): error C3203: 'if_' : unspecialized class template can't be used as a template argument for template parameter 'T3', expected a real type
2>C:\cpp-netlib\branch\boost/network/constants.hpp(151): error C2955: 'boost::mpl::if_' : use of class template requires template argument list
2> C:\boost\include\boost/mpl/if.hpp(56) : see declaration of 'boost::mpl::if_'
2>C:\cpp-netlib\branch\boost/network/constants.hpp(152): error C2143: syntax error : missing ',' before '>'

The file is unmodified (constants.hpp) and is a week old.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See how it's used everywhere else then use it the same way here.


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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point of removing the trailing '/'? This is not part of normalization of URIs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the simple reason why: "dir/sub/" is often the same path as "dir/sub". But I can remove it.


return path;
}

//A simple helper method, deduce const wchar_t/char * to std::basic_string<char/wchar_t>
template <typename Type>
inline std::basic_string<Type> normalize(const Type* path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we supporting bare pointers here? I would rather this not be implemented and make normalize actually mutate an existing path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I skip this part cannot visual studio deduce compile arguments: "could not deduce template argument for..." and will generate errors for a call like this: normalize("const char* here").The method will only simply convert a const char* or const wchar_t* to its corresponding string implementation, what is wrong with that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's wrong with that, is that you shouldn't really be supporting raw pointers. If someone wants to normalize a string or a wide string you do this:

template <class Type>
void normalize(Type &path);

{
return normalize(std::basic_string<Type>(path));
}
}
}
}

#endif
20 changes: 19 additions & 1 deletion libs/network/test/uri/uri_test.cpp
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -9,6 +10,7 @@
#include <boost/network/uri.hpp>
#include <boost/network/uri/uri.hpp>
#include <boost/network/uri/uri_io.hpp>
#include <boost/network/uri/normalize.hpp>
#include <boost/range/algorithm/equal.hpp>
#include <boost/scoped_ptr.hpp>
#include <map>
Expand Down Expand Up @@ -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");
}