Imported Upstream version 17.25.4
[platform/upstream/libzypp.git] / tests / zypp / Url_test.cc
1 /*
2 ** Check if the url by scheme repository works, e.g.
3 ** if there are some initialization order problems
4 ** (ViewOption) causing asString to format its string
5 ** differently than configured.
6 */
7
8 #include <zypp/base/Exception.h>
9 #include <zypp/base/String.h>
10
11 #include <zypp/RepoInfo.h>
12
13 #include <zypp/Url.h>
14 #include <stdexcept>
15 #include <iostream>
16 #include <cassert>
17
18 // Boost.Test
19 #include <boost/test/unit_test.hpp>
20
21 using boost::unit_test::test_case;
22 using namespace zypp;
23
24 void testUrlAuthority( const Url & url_r,
25                        const std::string & host_r, const std::string & port_r = std::string(),
26                        const std::string & user_r = std::string(), const std::string & pass_r = std::string() )
27 {
28   BOOST_CHECK_EQUAL( url_r.getUsername(),       user_r );
29   BOOST_CHECK_EQUAL( url_r.getPassword(),       pass_r );
30   BOOST_CHECK_EQUAL( url_r.getHost(),           host_r );
31   BOOST_CHECK_EQUAL( url_r.getPort(),           port_r );
32 }
33
34
35 BOOST_AUTO_TEST_CASE(test_ipv6_url)
36 {
37     std::string str;
38     zypp::Url   url;
39
40     str = "http://[2001:DB8:0:F102::1]/64/sles11/RC1/CD1?device=eth0";
41     url = Url( str );
42     BOOST_CHECK_EQUAL( str,url.asString() );
43     testUrlAuthority( url, "[2001:DB8:0:F102::1]", "", "", "" );
44
45     // bnc#
46     str = "http://[2001:DB8:0:F102::1]:8080/64/sles11/RC1/CD1?device=eth0";
47     url = Url( str );
48     testUrlAuthority( url, "[2001:DB8:0:F102::1]", "8080", "", "" );
49
50
51     str = "http://user:pass@[2001:DB8:0:F102::1]:8080/64/sles11/RC1/CD1?device=eth0";
52     url = Url( str );
53     testUrlAuthority( url, "[2001:DB8:0:F102::1]", "8080", "user", "pass" );
54 }
55
56 BOOST_AUTO_TEST_CASE(test_url1)
57 {
58     std::string str, one, two;
59     zypp::Url   url;
60
61
62     // asString & asCompleteString should not print "mailto://"
63     str = "mailto:feedback@example.com?subject=hello";
64     url = str;
65     BOOST_CHECK_EQUAL( str, url.asString() );
66     BOOST_CHECK_EQUAL( str, url.asCompleteString() );
67
68     // In general, schema without authority allows specifying an empty authority
69     // though it should not be printed (unless explicitly requested).
70     BOOST_CHECK_EQUAL( Url("dvd:/srv/ftp").asCompleteString(),   "dvd:/srv/ftp" );
71     BOOST_CHECK_EQUAL( Url("dvd:/srv/ftp").asString(),           "dvd:/srv/ftp" );
72
73     BOOST_CHECK_EQUAL( Url("dvd:///srv/ftp").asCompleteString(), "dvd:/srv/ftp" );
74     BOOST_CHECK_EQUAL( Url("dvd:///srv/ftp").asString(),         "dvd:/srv/ftp" );
75
76     BOOST_CHECK_EQUAL( Url("dvd:///srv/ftp").asString(url::ViewOption::DEFAULTS+url::ViewOption::EMPTY_AUTHORITY),        "dvd:///srv/ftp" );
77     BOOST_CHECK_EQUAL( Url("dvd:///srv/ftp").asString(url::ViewOption::DEFAULTS-url::ViewOption::EMPTY_AUTHORITY),        "dvd:/srv/ftp" );
78
79     BOOST_CHECK_THROW( Url("dvd://authority/srv/ftp"), url::UrlNotAllowedException );
80
81     // asString shouldn't print the password, asCompleteString should
82     // further, the "//" at the begin of the path should become "/%2F"
83     str = "ftp://user:pass@localhost//srv/ftp";
84     one = "ftp://user@localhost/%2Fsrv/ftp";
85     two = "ftp://user:pass@localhost/%2Fsrv/ftp";
86     url = str;
87
88     BOOST_CHECK_EQUAL( one, url.asString() );
89     BOOST_CHECK_EQUAL( two, url.asCompleteString() );
90
91     // asString shouldn't print the password, asCompleteString should.
92     // further, the "//" at the begin of the path should be keept.
93     str = "http://user:pass@localhost//srv/ftp?proxypass=@PROXYPASS@&proxy=proxy.my&proxyuser=@PROXYUSER@&Xproxypass=NOTTHIS&proxypass=@PROXYPASS@&proxypass=@PROXYPASS@";
94     one = "http://user@localhost//srv/ftp?proxy=proxy.my&proxyuser=@PROXYUSER@&Xproxypass=NOTTHIS";
95     two = str;
96     url = str;
97
98     BOOST_CHECK_EQUAL( one, url.asString() );
99     BOOST_CHECK_EQUAL( two, url.asCompleteString() );
100     // hidden proxypass in the query is available when explicitely asked for
101     BOOST_CHECK_EQUAL( url.getQueryParam( "proxypass" ), "@PROXYPASS@" );
102
103     // absolute path defaults to 'file://'
104     str = "/some/local/path";
105     BOOST_CHECK_EQUAL( zypp::Url(str).asString(), "file://"+str );
106
107     str = "file:./srv/ftp";
108     BOOST_CHECK_EQUAL( zypp::Url(str).asString(), str );
109
110     str = "ftp://foo//srv/ftp";
111     BOOST_CHECK_EQUAL( zypp::Url(str).asString(), "ftp://foo/%2Fsrv/ftp" );
112
113     str = "FTP://user@local%68ost/%2f/srv/ftp";
114     BOOST_CHECK_EQUAL( zypp::Url(str).asString(), "ftp://user@localhost/%2f/srv/ftp" );
115
116     str = "http://[::1]/foo/bar";
117     BOOST_CHECK_EQUAL( str, zypp::Url(str).asString() );
118
119     str = "http://:@just-localhost.example.net:8080/";
120     BOOST_CHECK_EQUAL( zypp::Url(str).asString(), "http://just-localhost.example.net:8080/" );
121
122     str = "mailto:feedback@example.com?subject=hello";
123     BOOST_CHECK_EQUAL( str, zypp::Url(str).asString() );
124
125     str = "nfs://nfs-server/foo/bar/trala";
126     BOOST_CHECK_EQUAL( str, zypp::Url(str).asString() );
127
128     str = "ldap://example.net/dc=example,dc=net?cn,sn?sub?(cn=*)#x";
129     BOOST_CHECK_THROW( zypp::Url(str).asString(), url::UrlNotAllowedException );
130
131     str = "ldap://example.net/dc=example,dc=net?cn,sn?sub?(cn=*)";
132     BOOST_CHECK_EQUAL( str, zypp::Url(str).asString() );
133
134     // parseable but invalid, since no host avaliable
135     str = "ldap:///dc=foo,dc=bar";
136     BOOST_CHECK_EQUAL( str, zypp::Url(str).asString());
137     BOOST_CHECK( !zypp::Url(str).isValid());
138
139     // throws:  host is mandatory
140     str = "ftp:///foo/bar";
141     BOOST_CHECK_THROW(zypp::Url(str).asString(), url::UrlNotAllowedException );
142
143     // throws:  host is mandatory
144     str = "http:///%2f/srv/ftp";
145     BOOST_CHECK_THROW(zypp::Url(str).asString(), url::UrlNotAllowedException );
146
147     // OK, host allowed in file-url
148     str = "file://localhost/some/path";
149     BOOST_CHECK_EQUAL( str, zypp::Url(str).asString());
150
151     // throws:  host not allowed
152     str = "cd://localhost/some/path";
153     BOOST_CHECK_THROW(zypp::Url(str).asString(), url::UrlNotAllowedException );
154
155     // throws: no path (email)
156     str = "mailto:";
157     BOOST_CHECK_THROW(zypp::Url(str).asString(), url::UrlNotAllowedException );
158
159     // throws:  no path
160     str = "cd:";
161     BOOST_CHECK_THROW(zypp::Url(str).asString(), url::UrlNotAllowedException );
162
163     // OK, valid (no host, path is there)
164     str = "cd:///some/path";
165     BOOST_CHECK( zypp::Url(str).isValid());
166 }
167
168 BOOST_AUTO_TEST_CASE(test_url2)
169 {
170   zypp::Url url("http://user:pass@localhost:/path/to;version=1.1?arg=val#frag");
171
172   BOOST_CHECK_EQUAL( url.asString(),
173   "http://user@localhost/path/to?arg=val#frag" );
174
175   BOOST_CHECK_EQUAL( url.asString(zypp::url::ViewOptions() +
176                      zypp::url::ViewOptions::WITH_PASSWORD),
177   "http://user:pass@localhost/path/to?arg=val#frag");
178
179   BOOST_CHECK_EQUAL( url.asString(zypp::url::ViewOptions() +
180                      zypp::url::ViewOptions::WITH_PATH_PARAMS),
181   "http://user@localhost/path/to;version=1.1?arg=val#frag");
182
183   BOOST_CHECK_EQUAL( url.asCompleteString(),
184   "http://user:pass@localhost/path/to;version=1.1?arg=val#frag");
185 }
186
187 BOOST_AUTO_TEST_CASE(test_url3)
188 {
189   zypp::Url   url("http://localhost/path/to#frag");
190   std::string key;
191   std::string val;
192
193   // will be encoded as "hoho=ha%20ha"
194   key = "hoho";
195   val = "ha ha";
196   url.setQueryParam(key, val);
197   BOOST_CHECK_EQUAL( url.asString(),
198   "http://localhost/path/to?hoho=ha%20ha#frag");
199
200   // will be encoded as "foo%3Dbar%26key=foo%26bar%3Dvalue"
201   key = "foo=bar&key";
202   val = "foo&bar=value";
203   url.setQueryParam(key, val);
204   BOOST_CHECK_EQUAL( url.asString(),
205   "http://localhost/path/to?foo%3Dbar%26key=foo%26bar%3Dvalue&hoho=ha%20ha#frag");
206
207   // will be encoded as "foo%25bar=is%25de%25ad"
208   key = "foo%bar";
209   val = "is%de%ad";
210   url.setQueryParam(key, val);
211   BOOST_CHECK_EQUAL( url.asString(),
212   "http://localhost/path/to?foo%25bar=is%25de%25ad&foo%3Dbar%26key=foo%26bar%3Dvalue&hoho=ha%20ha#frag");
213
214   // get encoded query parameters and compare with results:
215   zypp::url::ParamVec params( url.getQueryStringVec());
216   const char * const  result[] = {
217     "foo%25bar=is%25de%25ad",
218     "foo%3Dbar%26key=foo%26bar%3Dvalue",
219     "hoho=ha%20ha"
220   };
221   BOOST_CHECK( params.size() == (sizeof(result)/sizeof(result[0])));
222   for( size_t i=0; i<params.size(); i++)
223   {
224       BOOST_CHECK_EQUAL( params[i], result[i]);
225   }
226 }
227
228 BOOST_AUTO_TEST_CASE( test_url4)
229 {
230   try
231   {
232     zypp::Url url("ldap://example.net/dc=example,dc=net?cn,sn?sub?(cn=*)");
233
234     // fetch query params as vector
235     zypp::url::ParamVec pvec( url.getQueryStringVec());
236     BOOST_CHECK( pvec.size() == 3);
237     BOOST_CHECK_EQUAL( pvec[0], "cn,sn");
238     BOOST_CHECK_EQUAL( pvec[1], "sub");
239     BOOST_CHECK_EQUAL( pvec[2], "(cn=*)");
240
241     // fetch the query params map
242     // with its special ldap names/keys
243     zypp::url::ParamMap pmap( url.getQueryStringMap());
244     zypp::url::ParamMap::const_iterator m;
245     for(m=pmap.begin(); m!=pmap.end(); ++m)
246     {
247       if("attrs"  == m->first)
248       {
249         BOOST_CHECK_EQUAL( m->second, "cn,sn");
250       }
251       else
252       if("filter" == m->first)
253       {
254         BOOST_CHECK_EQUAL( m->second, "(cn=*)");
255       }
256       else
257       if("scope"  == m->first)
258       {
259         BOOST_CHECK_EQUAL( m->second, "sub");
260       }
261       else
262       {
263         BOOST_FAIL("Unexpected LDAP query parameter name in the map!");
264       }
265     }
266
267     url.setQueryParam("attrs", "cn,sn,uid");
268     url.setQueryParam("filter", "(|(sn=foo)(cn=bar))");
269
270     BOOST_CHECK_EQUAL(url.getQueryParam("attrs"),  "cn,sn,uid");
271     BOOST_CHECK_EQUAL(url.getQueryParam("filter"), "(|(sn=foo)(cn=bar))");
272
273   }
274   catch(const zypp::url::UrlException &e)
275   {
276     ZYPP_CAUGHT(e);
277   }
278 }
279
280 BOOST_AUTO_TEST_CASE( test_url5)
281 {
282   std::string str( "file:/some/${var:+path}/${var:-with}/${vars}" );
283   BOOST_CHECK_EQUAL( Url(str).asString(), str );
284   BOOST_CHECK_EQUAL( Url(zypp::url::encode( str, URL_SAFE_CHARS )).asString(), str );
285 }
286
287 BOOST_AUTO_TEST_CASE(plugin_scriptpath)
288 {
289   // plugin script path must not be rewritten
290   for ( const std::string & t : { "script", "script/", "/script", "/script/", "./script", "./script/" } )
291   {
292     BOOST_CHECK_EQUAL( Url("plugin:"+t).getPathName(),  t );
293   }
294
295   { // more cosmetic issue, but the RepoVarReplacer should
296     // not change the string representation (-> "plugin:/script")
297     Url u( "plugin:script?opt=val" );
298     RepoInfo i;
299     i.setBaseUrl( u );
300     BOOST_CHECK_EQUAL( u.asString(), i.url().asString() );
301   }
302
303 }
304
305 BOOST_AUTO_TEST_CASE(plugin_querystring_args)
306 {
307   // url querysting options without value must be possible
308   // e.g. for plugin schema
309   Url u( "plugin:script?loptv=lvalue&v=optv&lopt=&o" );
310   url::ParamMap pm( u.getQueryStringMap() );
311   BOOST_CHECK_EQUAL( pm.size(), 4 );
312   BOOST_CHECK_EQUAL( pm["loptv"], "lvalue" );
313   BOOST_CHECK_EQUAL( pm["v"], "optv" );
314   BOOST_CHECK_EQUAL( pm["lopt"], "" );
315   BOOST_CHECK_EQUAL( pm["o"], "" );
316 }
317
318 // vim: set ts=2 sts=2 sw=2 ai et: