Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
9caf90f7
Commit
9caf90f7
authored
Sep 07, 2019
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
util/UriRelative: add uri_apply_relative()
parent
71448e64
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
154 additions
and
0 deletions
+154
-0
UriRelative.cxx
src/util/UriRelative.cxx
+105
-0
UriRelative.hxx
src/util/UriRelative.hxx
+5
-0
TestUriRelative.cxx
test/TestUriRelative.cxx
+44
-0
No files found.
src/util/UriRelative.cxx
View file @
9caf90f7
...
...
@@ -28,6 +28,7 @@
*/
#include "UriRelative.hxx"
#include "UriExtract.hxx"
#include "StringAPI.hxx"
#include "StringCompare.hxx"
...
...
@@ -82,3 +83,107 @@ uri_apply_base(const std::string &uri, const std::string &base) noexcept
out
+=
uri
;
return
out
;
}
static
void
ClearFilename
(
StringView
&
path
)
noexcept
{
const
char
*
slash
=
path
.
FindLast
(
'/'
);
if
(
slash
!=
nullptr
)
path
.
SetEnd
(
slash
+
1
);
else
path
.
size
=
0
;
}
static
bool
ConsumeLastSegment
(
StringView
&
path
)
noexcept
{
assert
(
!
path
.
empty
());
assert
(
path
.
back
()
==
'/'
);
path
.
pop_back
();
const
char
*
slash
=
path
.
FindLast
(
'/'
);
if
(
slash
==
nullptr
)
return
false
;
path
.
SetEnd
(
slash
+
1
);
return
true
;
}
static
bool
ConsumeSpecial
(
const
char
*&
relative_path
,
StringView
&
base_path
)
noexcept
{
while
(
true
)
{
if
(
const
char
*
a
=
StringAfterPrefix
(
relative_path
,
"./"
))
{
while
(
*
a
==
'/'
)
++
a
;
relative_path
=
a
;
}
else
if
(
const
char
*
b
=
StringAfterPrefix
(
relative_path
,
"../"
))
{
while
(
*
b
==
'/'
)
++
b
;
relative_path
=
b
;
if
(
!
ConsumeLastSegment
(
base_path
))
return
false
;
}
else
if
(
StringIsEqual
(
relative_path
,
"."
))
{
++
relative_path
;
return
true
;
}
else
return
true
;
}
}
std
::
string
uri_apply_relative
(
const
std
::
string
&
relative_uri
,
const
std
::
string
&
base_uri
)
noexcept
{
if
(
relative_uri
.
empty
())
return
base_uri
;
if
(
uri_has_scheme
(
relative_uri
.
c_str
()))
return
relative_uri
;
const
char
*
relative_path
=
relative_uri
.
c_str
();
// TODO: support double slash at beginning of relative_uri
if
(
relative_uri
.
front
()
==
'/'
)
{
/* absolute path: replace the whole URI path in base */
auto
i
=
base_uri
.
find
(
"://"
);
if
(
i
==
base_uri
.
npos
)
/* no scheme: override base completely */
return
relative_uri
;
/* find the first slash after the host part */
i
=
base_uri
.
find
(
'/'
,
i
+
3
);
if
(
i
==
base_uri
.
npos
)
/* there's no URI path - simply append uri */
i
=
base_uri
.
length
();
return
base_uri
.
substr
(
0
,
i
)
+
relative_uri
;
}
const
char
*
_base_path
=
uri_get_path
(
base_uri
.
c_str
());
if
(
_base_path
==
nullptr
)
{
std
::
string
result
(
base_uri
);
if
(
relative_uri
.
front
()
!=
'/'
)
result
.
push_back
(
'/'
);
while
(
const
char
*
a
=
StringAfterPrefix
(
relative_path
,
"./"
))
relative_path
=
a
;
if
(
StringStartsWith
(
relative_path
,
"../"
))
return
{};
if
(
!
StringIsEqual
(
relative_path
,
"."
))
result
+=
relative_uri
;
return
result
;
}
StringView
base_path
(
_base_path
);
ClearFilename
(
base_path
);
if
(
!
ConsumeSpecial
(
relative_path
,
base_path
))
return
{};
std
::
string
result
(
base_uri
.
c_str
(),
_base_path
);
result
.
append
(
base_path
.
data
,
base_path
.
size
);
result
.
append
(
relative_path
);
return
result
;
}
src/util/UriRelative.hxx
View file @
9caf90f7
...
...
@@ -55,4 +55,9 @@ gcc_pure
std
::
string
uri_apply_base
(
const
std
::
string
&
uri
,
const
std
::
string
&
base
)
noexcept
;
gcc_pure
std
::
string
uri_apply_relative
(
const
std
::
string
&
relative_uri
,
const
std
::
string
&
base_uri
)
noexcept
;
#endif
test/TestUriRelative.cxx
View file @
9caf90f7
...
...
@@ -50,3 +50,47 @@ TEST(UriRelative, ApplyBase)
EXPECT_STREQ
(
uri_apply_base
(
i
.
uri
,
i
.
base
).
c_str
(),
i
.
result
);
}
}
TEST
(
UriRelative
,
ApplyRelative
)
{
static
constexpr
struct
{
const
char
*
relative
;
const
char
*
base
;
const
char
*
result
;
}
tests
[]
=
{
{
""
,
"bar"
,
"bar"
},
{
"."
,
"bar"
,
""
},
{
"foo"
,
"bar"
,
"foo"
},
{
""
,
"/bar"
,
"/bar"
},
{
"."
,
"/bar"
,
"/"
},
{
"foo"
,
"/bar"
,
"/foo"
},
{
""
,
"/bar/"
,
"/bar/"
},
{
"."
,
"/bar/"
,
"/bar/"
},
{
"."
,
"/bar/foo"
,
"/bar/"
},
{
"/foo"
,
"/bar/"
,
"/foo"
},
{
"foo"
,
"/bar/"
,
"/bar/foo"
},
{
"../foo"
,
"/bar/"
,
"/foo"
},
{
"./foo"
,
"/bar/"
,
"/bar/foo"
},
{
"./../foo"
,
"/bar/"
,
"/foo"
},
{
".././foo"
,
"/bar/"
,
"/foo"
},
{
"../../foo"
,
"/bar/"
,
""
},
{
"/foo"
,
"http://localhost/bar/"
,
"http://localhost/foo"
},
{
"/foo"
,
"http://localhost/bar"
,
"http://localhost/foo"
},
{
"/foo"
,
"http://localhost/"
,
"http://localhost/foo"
},
{
"/foo"
,
"http://localhost"
,
"http://localhost/foo"
},
{
"/"
,
"http://localhost"
,
"http://localhost/"
},
{
"/"
,
"http://localhost/bar"
,
"http://localhost/"
},
{
"/"
,
"http://localhost/bar/"
,
"http://localhost/"
},
{
"/"
,
"http://localhost/bar/foo"
,
"http://localhost/"
},
{
"../foo"
,
"http://localhost/bar/"
,
"http://localhost/foo"
},
{
"../foo"
,
"http://localhost/bar"
,
""
},
{
"../foo"
,
"http://localhost/"
,
""
},
{
"../foo"
,
"http://localhost"
,
""
},
{
"."
,
"http://localhost"
,
"http://localhost/"
},
};
for
(
const
auto
&
i
:
tests
)
{
EXPECT_STREQ
(
uri_apply_relative
(
i
.
relative
,
i
.
base
).
c_str
(),
i
.
result
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment