CStringA CPathUtils::GetAbsoluteURL ( const CStringA& URL , const CStringA& repositoryRootURL , const CStringA& parentPathURL) { CStringA errorResult; SVNPool pool; /* If the URL is already absolute, there is nothing to do. */ const char *canonicalized_url = svn_uri_canonicalize (URL, pool); if (svn_path_is_url (canonicalized_url)) return canonicalized_url; /* Parse the parent directory URL into its parts. */ apr_uri_t parent_dir_parsed_uri; if (apr_uri_parse (pool, parentPathURL, &parent_dir_parsed_uri)) return errorResult; /* If the parent directory URL is at the server root, then the URL may have no / after the hostname so apr_uri_parse() will leave the URL's path as NULL. */ if (! parent_dir_parsed_uri.path) parent_dir_parsed_uri.path = apr_pstrmemdup (pool, "/", 1); /* Handle URLs relative to the current directory or to the repository root. The backpaths may only remove path elements, not the hostname. This allows an external to refer to another repository in the same server relative to the location of this repository, say using SVNParentPath. */ if ((0 == strncmp("../", URL, 3)) || (0 == strncmp("^/", URL, 2))) { apr_array_header_t *base_components = NULL; apr_array_header_t *relative_components = NULL; /* Decompose either the parent directory's URL path or the repository root's URL path into components. */ if (0 == strncmp ("../", URL, 3)) { base_components = svn_path_decompose (parent_dir_parsed_uri.path, pool); relative_components = svn_path_decompose (canonicalized_url, pool); } else { apr_uri_t repos_root_parsed_uri; if (apr_uri_parse(pool, repositoryRootURL, &repos_root_parsed_uri)) return errorResult; /* If the repository root URL is at the server root, then the URL may have no / after the hostname so apr_uri_parse() will leave the URL's path as NULL. */ if (! repos_root_parsed_uri.path) repos_root_parsed_uri.path = apr_pstrmemdup (pool, "/", 1); base_components = svn_path_decompose (repos_root_parsed_uri.path, pool); relative_components = svn_path_decompose (canonicalized_url + 2, pool); } for (int i = 0; i < relative_components->nelts; ++i) { const char *component = APR_ARRAY_IDX(relative_components, i, const char *); if (0 == strcmp("..", component)) { /* Constructing the final absolute URL together with apr_uri_unparse() requires that the path be absolute, so only pop a component if the component being popped is not the component for the root directory. */ if (base_components->nelts > 1) apr_array_pop (base_components); } else APR_ARRAY_PUSH (base_components, const char *) = component; } parent_dir_parsed_uri.path = (char *)svn_path_compose(base_components, pool); parent_dir_parsed_uri.query = NULL; parent_dir_parsed_uri.fragment = NULL; return apr_uri_unparse (pool, &parent_dir_parsed_uri, 0); }
static svn_error_t * resolve_relative_external_url(const char **resolved_url, const svn_wc_external_item2_t *item, const char *repos_root_url, const char *parent_dir_url, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *url = item->url; apr_uri_t parent_dir_uri; apr_status_t status; *resolved_url = item->url; /* If the URL is already absolute, there is nothing to do. */ if (svn_path_is_url(url)) { /* "http://server/path" */ *resolved_url = svn_uri_canonicalize(url, result_pool); return SVN_NO_ERROR; } if (url[0] == '/') { /* "/path", "//path", and "///path" */ int num_leading_slashes = 1; if (url[1] == '/') { num_leading_slashes++; if (url[2] == '/') num_leading_slashes++; } /* "//schema-relative" and in some cases "///schema-relative". This last format is supported on file:// schema relative. */ url = apr_pstrcat(scratch_pool, apr_pstrndup(scratch_pool, url, num_leading_slashes), svn_relpath_canonicalize(url + num_leading_slashes, scratch_pool), (char*)NULL); } else { /* "^/path" and "../path" */ url = svn_relpath_canonicalize(url, scratch_pool); } /* Parse the parent directory URL into its parts. */ status = apr_uri_parse(scratch_pool, parent_dir_url, &parent_dir_uri); if (status) return svn_error_createf(SVN_ERR_BAD_URL, 0, "Illegal parent directory URL '%s'", parent_dir_url); /* If the parent directory URL is at the server root, then the URL may have no / after the hostname so apr_uri_parse() will leave the URL's path as NULL. */ if (! parent_dir_uri.path) parent_dir_uri.path = apr_pstrmemdup(scratch_pool, "/", 1); parent_dir_uri.query = NULL; parent_dir_uri.fragment = NULL; /* Handle URLs relative to the current directory or to the repository root. The backpaths may only remove path elements, not the hostname. This allows an external to refer to another repository in the same server relative to the location of this repository, say using SVNParentPath. */ if ((0 == strncmp("../", url, 3)) || (0 == strncmp("^/", url, 2))) { apr_array_header_t *base_components; apr_array_header_t *relative_components; int i; /* Decompose either the parent directory's URL path or the repository root's URL path into components. */ if (0 == strncmp("../", url, 3)) { base_components = svn_path_decompose(parent_dir_uri.path, scratch_pool); relative_components = svn_path_decompose(url, scratch_pool); } else { apr_uri_t repos_root_uri; status = apr_uri_parse(scratch_pool, repos_root_url, &repos_root_uri); if (status) return svn_error_createf(SVN_ERR_BAD_URL, 0, "Illegal repository root URL '%s'", repos_root_url); /* If the repository root URL is at the server root, then the URL may have no / after the hostname so apr_uri_parse() will leave the URL's path as NULL. */ if (! repos_root_uri.path) repos_root_uri.path = apr_pstrmemdup(scratch_pool, "/", 1); base_components = svn_path_decompose(repos_root_uri.path, scratch_pool); relative_components = svn_path_decompose(url + 2, scratch_pool); } for (i = 0; i < relative_components->nelts; ++i) { const char *component = APR_ARRAY_IDX(relative_components, i, const char *); if (0 == strcmp("..", component)) { /* Constructing the final absolute URL together with apr_uri_unparse() requires that the path be absolute, so only pop a component if the component being popped is not the component for the root directory. */ if (base_components->nelts > 1) apr_array_pop(base_components); } else APR_ARRAY_PUSH(base_components, const char *) = component; } parent_dir_uri.path = (char *)svn_path_compose(base_components, scratch_pool); *resolved_url = svn_uri_canonicalize(apr_uri_unparse(scratch_pool, &parent_dir_uri, 0), result_pool); return SVN_NO_ERROR; }