monotone

monotone Mtn Source Tree

Root/uri.cc

1// Copyright (C) 2006 Graydon Hoare <graydon@pobox.com>
2//
3// This program is made available under the GNU GPL version 2.0 or
4// greater. See the accompanying file COPYING for details.
5//
6// This program is distributed WITHOUT ANY WARRANTY; without even the
7// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8// PURPOSE.
9
10#include <string>
11
12#include <boost/regex.hpp>
13
14#include "sanity.hh"
15#include "uri.hh"
16
17using std::string;
18
19bool
20parse_uri(string const & in, uri & out)
21{
22 uri u;
23
24 // This is a simplified URI grammar. It does the basics.
25
26 string scheme_part = "(?:([^:/?#]+):)?";
27 string authority_part = "(?://([^/?#]*))?";
28 string path_part = "([^?#]*)";
29 string query_part = "(?:\\?([^#]*))?";
30 string fragment_part = "(?:#(.*))?";
31
32 string uri_rx = (string("^")
33 + scheme_part
34 + authority_part
35 + path_part
36 + query_part
37 + fragment_part
38 + "$");
39
40 boost::match_results<std::string::const_iterator> uri_matches;
41 if (boost::regex_match(in, uri_matches, boost::regex(uri_rx)))
42 {
43
44 u.scheme = uri_matches.str(1);
45
46 // The "authority" fragment gets a bit more post-processing.
47 L(FL("matched URI scheme: '%s'") % u.scheme);
48
49 if (uri_matches[2].matched)
50{
51 string authority = uri_matches.str(2);
52 L(FL("matched URI authority: '%s'") % authority);
53
54 string user_part = "(?:([^@]+)@)?";
55 string ipv6_host_part = "\\[([^\\]]+)]\\]";
56 string normal_host_part = "([^:/]+)";
57 string host_part = "(?:" + ipv6_host_part + "|" + normal_host_part + ")";
58 string port_part = "(?::([[:digit:]]+))?";
59 string auth_rx = user_part + host_part + port_part;
60 boost::match_results<std::string::const_iterator> auth_matches;
61 I(boost::regex_match(authority, auth_matches, boost::regex(auth_rx)));
62 u.user = auth_matches.str(1);
63 u.port = auth_matches.str(4);
64 if (auth_matches[2].matched)
65 u.host = auth_matches.str(2);
66 else
67 {
68 I(auth_matches[3].matched);
69 u.host = auth_matches.str(3);
70 }
71 L(FL("matched URI user: '%s'") % u.user);
72 L(FL("matched URI host: '%s'") % u.host);
73 L(FL("matched URI port: '%s'") % u.port);
74
75}
76
77 u.path = uri_matches.str(3);
78 u.query = uri_matches.str(4);
79 u.fragment = uri_matches.str(5);
80 L(FL("matched URI path: '%s'") % u.path);
81 L(FL("matched URI query: '%s'") % u.query);
82 L(FL("matched URI fragment: '%s'") % u.fragment);
83 out = u;
84 return true;
85 }
86 else
87 return false;
88}
89
90
91
92#ifdef BUILD_UNIT_TESTS
93#include "unit_tests.hh"
94#include "transforms.hh"
95
96static void
97test_one_uri(string scheme,
98 string user,
99 string ipv6_host,
100 string normal_host,
101 string port,
102 string path,
103 string query,
104 string fragment)
105{
106 string built;
107
108 if (!scheme.empty())
109 built += scheme + ':';
110
111 string host;
112
113 if (! ipv6_host.empty())
114 {
115 I(normal_host.empty());
116 host += '[';
117 host += (ipv6_host + ']');
118 }
119 else
120 host = normal_host;
121
122 if (! (user.empty()
123 && host.empty()
124 && port.empty()))
125 {
126 built += "//";
127
128 if (! user.empty())
129built += (user + '@');
130
131 if (! host.empty())
132built += host;
133
134 if (! port.empty())
135{
136 built += ':';
137 built += port;
138}
139 }
140
141 if (! path.empty())
142 {
143 I(path[0] == '/');
144 built += path;
145 }
146
147 if (! query.empty())
148 {
149 built += '?';
150 built += query;
151 }
152
153 if (! fragment.empty())
154 {
155 built += '#';
156 built += fragment;
157 }
158
159 L(FL("testing parse of URI '%s'") % built);
160 uri u;
161 BOOST_CHECK(parse_uri(built, u));
162 BOOST_CHECK(u.scheme == scheme);
163 BOOST_CHECK(u.user == user);
164 BOOST_CHECK(u.host == host);
165 BOOST_CHECK(u.port == port);
166 BOOST_CHECK(u.path == path);
167 BOOST_CHECK(u.query == query);
168 BOOST_CHECK(u.fragment == fragment);
169}
170
171
172static void
173uri_test()
174{
175 test_one_uri("ssh", "graydon", "", "venge.net", "22", "/tmp/foo.mtn", "", "");
176 test_one_uri("ssh", "graydon", "", "venge.net", "", "/tmp/foo.mtn", "", "");
177 test_one_uri("ssh", "", "", "venge.net", "22", "/tmp/foo.mtn", "", "");
178 test_one_uri("ssh", "", "", "venge.net", "", "/tmp/foo.mtn", "", "");
179 test_one_uri("file", "", "", "", "", "/tmp/foo.mtn", "", "");
180 test_one_uri("", "", "", "", "", "/tmp/foo.mtn", "", "");
181 test_one_uri("http", "graydon", "", "venge.net", "8080", "/foo.cgi", "branch=foo", "tip");
182}
183
184
185void
186add_uri_tests(test_suite * suite)
187{
188 I(suite);
189 suite->add(BOOST_TEST_CASE(&uri_test));
190}
191
192#endif // BUILD_UNIT_TESTS
193
194// Local Variables:
195// mode: C++
196// fill-column: 76
197// c-file-style: "gnu"
198// indent-tabs-mode: nil
199// End:
200// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status