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
11#include "base.hh"
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
62 N(boost::regex_match(authority, auth_matches, boost::regex(auth_rx)),
63 F("The URI syntax is invalid. Maybe you used an URI in scp-style?"));
64
65 u.user = auth_matches.str(1);
66 u.port = auth_matches.str(4);
67 if (auth_matches[2].matched)
68 u.host = auth_matches.str(2);
69 else
70 {
71 I(auth_matches[3].matched);
72 u.host = auth_matches.str(3);
73 }
74 L(FL("matched URI user: '%s'") % u.user);
75 L(FL("matched URI host: '%s'") % u.host);
76 L(FL("matched URI port: '%s'") % u.port);
77
78}
79
80 u.path = uri_matches.str(3);
81 u.query = uri_matches.str(4);
82 u.fragment = uri_matches.str(5);
83 L(FL("matched URI path: '%s'") % u.path);
84 L(FL("matched URI query: '%s'") % u.query);
85 L(FL("matched URI fragment: '%s'") % u.fragment);
86 out = u;
87 return true;
88 }
89 else
90 return false;
91}
92
93
94
95#ifdef BUILD_UNIT_TESTS
96#include "unit_tests.hh"
97#include "transforms.hh"
98
99static void
100test_one_uri(string scheme,
101 string user,
102 string ipv6_host,
103 string normal_host,
104 string port,
105 string path,
106 string query,
107 string fragment)
108{
109 string built;
110
111 if (!scheme.empty())
112 built += scheme + ':';
113
114 string host;
115
116 if (! ipv6_host.empty())
117 {
118 I(normal_host.empty());
119 host += '[';
120 host += (ipv6_host + ']');
121 }
122 else
123 host = normal_host;
124
125 if (! (user.empty()
126 && host.empty()
127 && port.empty()))
128 {
129 built += "//";
130
131 if (! user.empty())
132built += (user + '@');
133
134 if (! host.empty())
135built += host;
136
137 if (! port.empty())
138{
139 built += ':';
140 built += port;
141}
142 }
143
144 if (! path.empty())
145 {
146 I(path[0] == '/');
147 built += path;
148 }
149
150 if (! query.empty())
151 {
152 built += '?';
153 built += query;
154 }
155
156 if (! fragment.empty())
157 {
158 built += '#';
159 built += fragment;
160 }
161
162 L(FL("testing parse of URI '%s'") % built);
163 uri u;
164 UNIT_TEST_CHECK(parse_uri(built, u));
165 UNIT_TEST_CHECK(u.scheme == scheme);
166 UNIT_TEST_CHECK(u.user == user);
167 UNIT_TEST_CHECK(u.host == host);
168 UNIT_TEST_CHECK(u.port == port);
169 UNIT_TEST_CHECK(u.path == path);
170 UNIT_TEST_CHECK(u.query == query);
171 UNIT_TEST_CHECK(u.fragment == fragment);
172}
173
174UNIT_TEST(uri, uri)
175{
176 test_one_uri("ssh", "graydon", "", "venge.net", "22", "/tmp/foo.mtn", "", "");
177 test_one_uri("ssh", "graydon", "", "venge.net", "", "/tmp/foo.mtn", "", "");
178 test_one_uri("ssh", "", "", "venge.net", "22", "/tmp/foo.mtn", "", "");
179 test_one_uri("ssh", "", "", "venge.net", "", "/tmp/foo.mtn", "", "");
180 test_one_uri("file", "", "", "", "", "/tmp/foo.mtn", "", "");
181 test_one_uri("", "", "", "", "", "/tmp/foo.mtn", "", "");
182 test_one_uri("http", "graydon", "", "venge.net", "8080", "/foo.cgi", "branch=foo", "tip");
183}
184
185#endif // BUILD_UNIT_TESTS
186
187// Local Variables:
188// mode: C++
189// fill-column: 76
190// c-file-style: "gnu"
191// indent-tabs-mode: nil
192// End:
193// 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