← 输入框|github.com|刷新
Skip to content

Refactor URI #18

Closed
Closed

Description

@glynos

IMO, the URI code can be refactored so it is less coupled with HTTP. e.g. basic_uri in boost/network/uri.hpp contains a lot of functionality that only applies to an HTTP uri. I think it would be better to have a boost::network::basic_uri provide only a very coarse URI, which might cover:

://?

This is related to issue #15. In order to get this done, perhaps we need to order the URI into this kind of structure:

boost/network/uri/uri.hpp // rfc 3986
boost/network/uri/http/uri.hpp // rfc
boost/network/uri/mailto/uri.hpp // rfc 2368

etc.

Activity

  1. glynos commented on Nov 1, 2010

    @glynos
    MemberAuthor

    I updated the URI tests and added some documentation and I have some comments based on what I have done.

    I had intended to implement #18 in the way described in the original report, but I have since changed my opinion. I still want to have an interface that allows accessing the authority or hierarchical part of a URI but the implementation makes that difficult, since it copies the elements into "uri_parts". What I would propose instead, is that uri_parts store iterator ranges instead of string copies. e.g.

    template <class Tag>
    struct uri_parts {
        typedef typename string<Tag>::type string_type;
        typedef typename string_type::const_iterator iterator_type;
        typedef boost::iterator_range<iterator_type> range_type;
    
        range_type scheme;
        range_type user_info;
        range_type host;
        range_type port;
        range_type path;
        range_type query;
        range_type fragment;
    };
    

    which means little change to the existing parser (which works extremely well, IMO) but allows us to extend the interface more easily without needing to know too much about the underlying string type.

    e.g. accessing the host as a string would be:

    template <class Tag>
    typename string<Tag>::type host(uri) {
        return string<Tag>::type(
            boost::begin(uri.parts.host), boost::end(uri.parts.host));
    }
    

    and we could add an "authority" accessor function:

    template <class Tag>
    typename string<Tag>::type authority(uri) {
        return string<Tag>::type(
            boost::begin(uri.parts.user_info), boost::end(uri.parts.port));
    }
    

    Does this make sense?

    Also, having looked at the HTTP URI, i'm not convinced of it's efficacy. It doesn't add any more that the approach I've described above can achieve. e.g.

    namespace http {
    template <class Tag>
    boost::uint16_t port(uri) {
        if (!uri.parts.port) {
             if (uri.parts.scheme == "http") {
                 return 80;
             }
             else if (uri.parts.scheme == "https") {
                 return 443;
             }
        }
        return construe_cast<boost::uint16_t>(
            string<Tag>::type(
                boost::begin(uri.parts.port), boost::end(uri.parts.port)));
    }
    } // namespace
    

    Also, I find the means of specializing the basic_uri template using the HTTP tag quite restrictive.

    I'm quite happy that the tests in boost/network/test/url_test.cpp are stable and reasonably comprehensive. Shall I push ahead? Does anyone see a flaw with what I described above?

  2. glynos commented on Nov 4, 2010

    @glynos
    MemberAuthor

    I have a pretty clear idea how I'd like to see this happen, either by defining a new class for each scheme and doing a 2nd scheme dependent parse in the constructor:

    namespace ftp {
    struct uri_parts {
        range_type username, password;
    };
    
    
    class basic_uri<Tag> : public boost::network::uri::basic_uri<Tag> {
       basic_uri(const string_type &uri) : base_type(uri) {
           // user_info => "username@password"
           parts.username = ... // first part of user_info
           parts.password = ... // 2nd part of user_info
       }
    
       uri_parts parts;
    };
    } // namespace
    

    or as described above using only uri::basic_uri, by providing specialist accessor function.

    namespace ftp {
    string_type username(uri) { return /*the bit before the @ in the user_info */ }
    // etc.
    } // namespace ftp
    

    I don't know how you could use tag dispatching here if you can only know the scheme at run-time.

    I won't work on this any more until the end of next week, so if you're planning on releasing 0.8 then this should wait.

    Its nice to be able to put up code examples here, on Github but this probably ought to move to the mailing list for a broader discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions