From ec9c6f1bbdfd3d86fba493ea56473c0aaf9acad1 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 29 Sep 2018 00:12:26 +0300 Subject: Add support for rootless URLs --- tests/url/driver.cxx | 86 +++++++++++++++++++++++++++++++++++++--------------- tests/url/testscript | 21 ++++++++++++- 2 files changed, 82 insertions(+), 25 deletions(-) (limited to 'tests') diff --git a/tests/url/driver.cxx b/tests/url/driver.cxx index 64bc2b5..dd124cd 100644 --- a/tests/url/driver.cxx +++ b/tests/url/driver.cxx @@ -33,7 +33,8 @@ enum class scheme { http, https, - file + file, + pkcs11 }; namespace butl @@ -47,37 +48,63 @@ namespace butl using scheme_type = scheme; using authority_type = basic_url_authority; - static scheme_type + static optional translate_scheme (const string_type& url, string_type&& scheme, - optional& /*authority*/, + optional& authority, optional& path, - optional& /*query*/, - optional& /*fragment*/) + optional& query, + optional& /*fragment*/, + bool& rootless) { - // Note that we must compare case-insensitive in the real program. - // - if (scheme == L"http") - return scheme_type::http; - else if (scheme == L"https") - return scheme_type::https; - else if (scheme == L"file") - return scheme_type::file; - else if (scheme.empty ()) + if (scheme.empty ()) { // If the URL looks like an absolute filesystem path, then translate it - // to the file URL. If it is not, then leave all the components absent - // to fail with a proper exception description. + // to the file URL. If it is not, then return nullopt to fail with a + // proper exception description. // wchar_t c; if ((c = url[0]) == '/' || (url.size () > 2 && alpha (c) && url[1] == ':' && url[2] == '/')) + { path = url; + rootless = false; + return scheme_type::file; + } - return scheme_type::file; + return nullopt; } + + scheme_type t; + + // Note that we must compare case-insensitive in the real program. + // + if (scheme == L"http") + t = scheme_type::http; + else if (scheme == L"https") + t = scheme_type::https; + else if (scheme == L"file") + t = scheme_type::file; + else if (scheme == L"pkcs11") + t = scheme_type::pkcs11; else throw invalid_argument ("unknown scheme"); + + if (t != scheme_type::pkcs11 && !authority && !path && !query) + throw invalid_argument ("no authority, path or query"); + + if (path) + { + if (t == scheme_type::pkcs11) + { + if (!rootless || path->find (L'/') != string_type::npos) + throw invalid_argument ("unexpected slash"); + } + else if (rootless) + throw invalid_argument ("rootless path"); + } + + return t; } // Translate scheme type back to its string representation. @@ -88,13 +115,15 @@ namespace butl const optional& /*authority*/, const optional& /*path*/, const optional& /*query*/, - const optional& /*fragment*/) + const optional& /*fragment*/, + bool /*rootless*/) { switch (scheme) { - case scheme_type::http: return L"http"; - case scheme_type::https: return L"https"; - case scheme_type::file: return L"file"; + case scheme_type::http: return L"http"; + case scheme_type::https: return L"https"; + case scheme_type::file: return L"file"; + case scheme_type::pkcs11: return L"pkcs11"; } assert (false); // Can't be here. @@ -104,11 +133,19 @@ namespace butl static path_type translate_path (string_type&& path) { - return path_type (move (path)); + // Note that a real pkcs11-supporting URL most likely would keep the + // path URL-encoded as its components can contain binary data. Or, it + // would split the path into components before decoding them. + // + return path_type (basic_url::decode (path)); } static string_type - translate_path (const path_type& path) {return string_type (path);} + translate_path (const path_type& path) + { + using url = basic_url; + return url::encode (path, [] (wchar_t& c) {return !url::path_char (c);}); + } }; } @@ -317,7 +354,8 @@ try nullopt, nullopt, nullopt, - nullopt) << endl; + nullopt, + false) << endl; } else wcout << L"[null]" << endl; diff --git a/tests/url/testscript b/tests/url/testscript index 4166007..05cc528 100644 --- a/tests/url/testscript +++ b/tests/url/testscript @@ -33,7 +33,6 @@ $* : { $* 'file:#f' 2>'no authority, path or query' != 0 : fragment - $* 'file:aaa' 2>'no authority, path or query' != 0 : junk $* 'file:' 2>'no authority, path or query' != 0 : none } @@ -324,6 +323,24 @@ $* [null] [null] EOO + + $* 'http:a/b/c' 2>'rootless path' != 0 : rootless-path + $* 'pkcs11:/abc' 2>'unexpected slash' != 0 : unexpected-slash1 + $* 'pkcs11:a/bc' 2>'unexpected slash' != 0 : unexpected-slash2 + } + + : rootless + : + { + : non-empty + : + $* 'pkcs11:token=sign;object=SIGN%20key' >>EOO + pkcs11 + [null] + token=sign;object=SIGN key + [null] + [null] + EOO } : query @@ -388,6 +405,8 @@ $* $* 'file:/b%7C2' >'file:/b%7C2' : path $* 'http://a?q=' >'http://a?q=' : query $* 'http://a#f' >'http://a#f' : fragment + + $* 'pkcs11:object=SIGN%20key' >'pkcs11:object=SIGN%20key' : rootless } : wstring -- cgit v1.1