Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
c03dd9b0
Commit
c03dd9b0
authored
Jul 09, 2018
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add percent encoding to URI
parent
1cada153
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
114 additions
and
64 deletions
+114
-64
libcaf_core/caf/detail/parser/read_uri.hpp
libcaf_core/caf/detail/parser/read_uri.hpp
+23
-15
libcaf_core/caf/detail/uri_impl.hpp
libcaf_core/caf/detail/uri_impl.hpp
+4
-0
libcaf_core/caf/uri.hpp
libcaf_core/caf/uri.hpp
+7
-6
libcaf_core/src/uri.cpp
libcaf_core/src/uri.cpp
+0
-27
libcaf_core/src/uri_impl.cpp
libcaf_core/src/uri_impl.cpp
+66
-16
libcaf_core/test/uri.cpp
libcaf_core/test/uri.cpp
+14
-0
No files found.
libcaf_core/caf/detail/parser/read_uri.hpp
View file @
c03dd9b0
...
...
@@ -105,6 +105,10 @@ void read_uri_query(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
fin
();
}
#define read_next_char(next_state) \
transition(next_state, unprotected_char, str += ch) \
fsm_transition(read_uri_percent_encoded(ps, str), next_state, '%')
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_uri
(
state
<
Iterator
,
Sentinel
>&
ps
,
Consumer
&&
consumer
)
{
// Local variables.
...
...
@@ -122,8 +126,8 @@ void read_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
auto
path_char
=
[](
char
c
)
{
return
in_whitelist
(
alphanumeric_chars
,
c
)
||
c
==
'/'
;
};
auto
authority
_char
=
[](
char
c
)
{
return
in_whitelist
(
alphanumeric_chars
,
c
)
||
c
==
'.'
;
auto
unprotected
_char
=
[](
char
c
)
{
return
in_whitelist
(
alphanumeric_chars
,
c
)
||
in_whitelist
(
"-._~"
,
c
)
;
};
// Utility setters for avoiding code duplication.
auto
set_path
=
[
&
]
{
...
...
@@ -148,13 +152,12 @@ void read_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
epsilon
(
read_scheme
)
}
state
(
read_scheme
)
{
fsm_transition
(
read_uri_percent_encoded
(
ps
,
str
),
read_scheme
,
'%'
)
transition
(
read_scheme
,
alphabetic_chars
,
str
+=
ch
)
read_next_char
(
read_scheme
)
transition
(
have_scheme
,
':'
,
consumer
.
scheme
(
take_str
()))
}
state
(
have_scheme
)
{
transition
(
disambiguate_path
,
'/'
)
transition
(
read_path
,
alphanumeric_chars
,
str
+=
c
h
)
read_next_char
(
read_pat
h
)
fsm_transition
(
read_uri_percent_encoded
(
ps
,
str
),
read_path
,
'%'
)
}
// This state is terminal, because "file:/" is a valid URI.
...
...
@@ -163,28 +166,32 @@ void read_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
epsilon
(
read_path
,
any_char
,
str
+=
'/'
)
}
state
(
start_authority
)
{
transition
(
read_authority
,
authority_char
,
str
+=
ch
)
fsm_transition
(
read_ipv6_address
(
ps
,
ip_consumer
),
end_of_ipv6_host
,
'['
)
read_next_char
(
read_authority
)
fsm_transition
(
read_ipv6_address
(
ps
,
ip_consumer
),
await_end_of_ipv6
,
'['
)
}
state
(
await_end_of_ipv6
)
{
transition
(
end_of_ipv6_host
,
']'
)
}
state
(
end_of_ipv6_host
)
{
transition
(
end_of_host
,
']'
)
term_state
(
end_of_ipv6_host
)
{
transition
(
start_port
,
':'
)
epsilon
(
end_of_authority
)
}
term_state
(
end_of_host
)
{
transition
(
start_port
,
':'
,
set_host
())
epsilon
(
end_of_authority
,
"/?#"
,
set_host
())
}
term_state
(
read_authority
,
set_host
())
{
transition
(
read_authority
,
authority_char
,
str
+=
ch
)
read_next_char
(
read_authority
)
transition
(
start_host
,
'@'
,
set_userinfo
())
transition
(
start_port
,
':'
,
set_host
())
epsilon
(
end_of_authority
,
"/?#"
,
set_host
())
}
state
(
start_host
)
{
transition
(
read_host
,
authority_char
,
str
+=
ch
)
fsm_transition
(
read_ipv6_address
(
ps
,
ip_consumer
),
end_of_ipv6_host
,
'['
)
read_next_char
(
read_host
)
fsm_transition
(
read_ipv6_address
(
ps
,
ip_consumer
),
await_end_of_ipv6
,
'['
)
}
term_state
(
read_host
,
set_host
())
{
transition
(
read_host
,
authority_char
,
str
+=
ch
)
read_next_char
(
read_host
)
transition
(
start_port
,
':'
,
set_host
())
epsilon
(
end_of_authority
,
"/?#"
,
set_host
())
}
...
...
@@ -194,7 +201,7 @@ void read_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
term_state
(
read_port
,
consumer
.
port
(
port
))
{
transition
(
read_port
,
decimal_chars
,
add_ascii
<
10
>
(
port
,
ch
),
pec
::
integer_overflow
)
epsilon
(
end_of_authority
,
"/?#"
,
set_host
()
)
epsilon
(
end_of_authority
,
"/?#"
)
}
term_state
(
end_of_authority
)
{
transition
(
read_path
,
'/'
)
...
...
@@ -203,6 +210,7 @@ void read_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
}
term_state
(
read_path
,
set_path
())
{
transition
(
read_path
,
path_char
,
str
+=
ch
)
fsm_transition
(
read_uri_percent_encoded
(
ps
,
str
),
read_path
,
'%'
)
transition
(
start_query
,
'?'
,
set_path
())
transition
(
read_fragment
,
'#'
,
set_path
())
}
...
...
@@ -214,7 +222,7 @@ void read_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
epsilon
(
done
)
}
term_state
(
read_fragment
,
consumer
.
fragment
(
take_str
()))
{
transition
(
read_fragment
,
alphanumeric_chars
,
str
+=
ch
)
read_next_char
(
read_fragment
)
}
term_state
(
done
)
{
// nop
...
...
libcaf_core/caf/detail/uri_impl.hpp
View file @
c03dd9b0
...
...
@@ -68,6 +68,10 @@ public:
/// Assembles the human-readable string representation for this URI.
void
assemble_str
();
// Escapes all reserved characters according to RFC 3986 in `x` and
// adds the encoded string to `str`.
void
add_encoded
(
string_view
x
,
bool
is_path
=
false
);
// -- friend functions -------------------------------------------------------
friend
void
intrusive_ptr_add_ref
(
const
uri_impl
*
p
);
...
...
libcaf_core/caf/uri.hpp
View file @
c03dd9b0
...
...
@@ -53,6 +53,13 @@ public:
inline
authority_type
()
:
port
(
0
)
{
// nop
}
/// Returns whether `host` is empty, i.e., the host is not an IP address
/// and the string is empty.
bool
empty
()
const
noexcept
{
auto
str
=
get_if
<
std
::
string
>
(
&
host
);
return
str
!=
nullptr
&&
str
->
empty
();
}
};
/// Separates the query component into key-value pairs.
...
...
@@ -110,12 +117,6 @@ private:
// -- related free functions ---------------------------------------------------
/// @relates uri
std
::
string
to_string
(
const
uri
::
host_type
&
x
);
/// @relates uri
std
::
string
to_string
(
const
uri
::
authority_type
&
x
);
/// @relates uri
std
::
string
to_string
(
const
uri
&
x
);
...
...
libcaf_core/src/uri.cpp
View file @
c03dd9b0
...
...
@@ -74,33 +74,6 @@ int uri::compare(string_view x) const noexcept {
// -- related free functions ---------------------------------------------------
std
::
string
to_string
(
const
uri
::
host_type
&
x
)
{
auto
str
=
get_if
<
std
::
string
>
(
&
x
);
if
(
str
)
return
*
str
;
auto
addr
=
get
<
ip_address
>
(
x
);
if
(
addr
.
embeds_v4
())
return
to_string
(
addr
.
embedded_v4
());
std
::
string
result
=
to_string
(
addr
);
result
.
insert
(
result
.
begin
(),
'['
);
result
+=
']'
;
return
result
;
}
std
::
string
to_string
(
const
uri
::
authority_type
&
x
)
{
std
::
string
result
;
if
(
!
x
.
userinfo
.
empty
())
{
result
+=
x
.
userinfo
;
result
+=
'@'
;
}
result
+=
to_string
(
x
.
host
);
if
(
x
.
port
!=
0
)
{
result
+=
':'
;
result
+=
std
::
to_string
(
x
.
port
);
}
return
result
;
}
std
::
string
to_string
(
const
uri
&
x
)
{
auto
x_str
=
x
.
str
();
std
::
string
result
{
x_str
.
begin
(),
x_str
.
end
()};
...
...
libcaf_core/src/uri_impl.cpp
View file @
c03dd9b0
...
...
@@ -39,40 +39,90 @@ uri_impl uri_impl::default_instance;
// -- modifiers ----------------------------------------------------------------
void
uri_impl
::
assemble_str
()
{
// TODO: all substrings need percent-escaping
str
=
scheme
;
add_encoded
(
scheme
);
str
+=
':'
;
auto
authority_str
=
to_string
(
authority
);
if
(
!
authority_str
.
empty
())
{
if
(
authority
.
empty
())
{
CAF_ASSERT
(
!
path
.
empty
());
add_encoded
(
path
,
true
);
}
else
{
str
+=
"//"
;
str
+=
authority_str
;
if
(
!
authority
.
userinfo
.
empty
())
{
add_encoded
(
authority
.
userinfo
);
str
+=
'@'
;
}
auto
addr
=
get_if
<
ip_address
>
(
&
authority
.
host
);
if
(
addr
==
nullptr
)
{
add_encoded
(
get
<
std
::
string
>
(
authority
.
host
));
}
else
{
str
+=
'['
;
str
+=
to_string
(
*
addr
);
str
+=
']'
;
}
if
(
authority
.
port
!=
0
)
{
str
+=
':'
;
str
+=
std
::
to_string
(
authority
.
port
);
}
if
(
!
path
.
empty
())
{
st
r
+=
'/'
;
str
+=
path
;
add
r
+=
'/'
;
add_encoded
(
path
,
true
)
;
}
}
else
if
(
!
path
.
empty
())
{
str
+=
path
;
}
if
(
!
query
.
empty
())
{
str
+=
'?'
;
auto
i
=
query
.
begin
();
str
+=
i
->
first
;
str
+=
'='
;
str
+=
i
->
second
;
auto
add_kvp
=
[
&
](
decltype
(
*
i
)
kvp
)
{
add_encoded
(
kvp
.
first
);
str
+=
'='
;
add_encoded
(
kvp
.
second
);
};
add_kvp
(
*
i
);
++
i
;
for
(;
i
!=
query
.
end
();
++
i
)
{
str
+=
'&'
;
str
+=
i
->
first
;
str
+=
'='
;
str
+=
i
->
second
;
add_kvp
(
*
i
);
}
}
if
(
!
fragment
.
empty
())
{
str
+=
'#'
;
str
+=
fragment
;
add_encoded
(
fragment
)
;
}
}
void
uri_impl
::
add_encoded
(
string_view
x
,
bool
is_path
)
{
for
(
auto
ch
:
x
)
switch
(
ch
)
{
case
'/'
:
if
(
is_path
)
{
str
+=
ch
;
break
;
}
case
' '
:
case
':'
:
case
'?'
:
case
'#'
:
case
'['
:
case
']'
:
case
'@'
:
case
'!'
:
case
'$'
:
case
'&'
:
case
'\''
:
case
'"'
:
case
'('
:
case
')'
:
case
'*'
:
case
'+'
:
case
','
:
case
';'
:
case
'='
:
str
+=
'%'
;
detail
::
append_hex
(
str
,
reinterpret_cast
<
uint8_t
*>
(
&
ch
),
1
);
break
;
default:
str
+=
ch
;
}
}
// -- friend functions ---------------------------------------------------------
void
intrusive_ptr_add_ref
(
const
uri_impl
*
p
)
{
...
...
libcaf_core/test/uri.cpp
View file @
c03dd9b0
...
...
@@ -202,6 +202,7 @@ CAF_TEST(constructing) {
CAF_CHECK_EQUAL(*(http << components), *(http_str << components))
CAF_TEST
(
builder
construction
)
{
// all combinations of components
BUILD
(
file
);
BUILD
(
file
<<
kvp
);
BUILD
(
file
<<
frag
);
...
...
@@ -238,11 +239,21 @@ CAF_TEST(builder construction) {
BUILD
(
me
<<
node
<<
port80
<<
file
<<
frag
);
BUILD
(
me
<<
node
<<
port80
<<
file
<<
kvp
);
BUILD
(
me
<<
node
<<
port80
<<
file
<<
kvp
<<
frag
);
// percent encoding
auto
escaped
=
uri_builder
{}
.
scheme
(
"hi there"
)
.
userinfo
(
"it's"
)
.
host
(
"me/"
)
.
path
(
"file 1"
)
.
fragment
(
"[42]"
)
.
make
();
CAF_CHECK_EQUAL
(
escaped
,
"hi%20there://it%27s@me%21/file%201#%5B42%5D"
);
}
#define ROUNDTRIP(str) CAF_CHECK_EQUAL(str##_u, str)
CAF_TEST
(
from
string
)
{
// all combinations of components
ROUNDTRIP
(
"http:file"
);
ROUNDTRIP
(
"http:file?a=1&b=2"
);
ROUNDTRIP
(
"http:file#42"
);
...
...
@@ -279,6 +290,7 @@ CAF_TEST(from string) {
ROUNDTRIP
(
"http://me@node:80/file?a=1&b=2"
);
ROUNDTRIP
(
"http://me@node:80/file#42"
);
ROUNDTRIP
(
"http://me@node:80/file?a=1&b=2#42"
);
// all combinations of with IPv6 host
ROUNDTRIP
(
"http://[::1]"
);
ROUNDTRIP
(
"http://[::1]?a=1&b=2"
);
ROUNDTRIP
(
"http://[::1]#42"
);
...
...
@@ -311,6 +323,8 @@ CAF_TEST(from string) {
ROUNDTRIP
(
"http://me@[::1]:80/file?a=1&b=2"
);
ROUNDTRIP
(
"http://me@[::1]:80/file#42"
);
ROUNDTRIP
(
"http://me@[::1]:80/file?a=1&b=2#42"
);
// percent encoding
ROUNDTRIP
(
"hi%20there://it%27s@me%21/file%201#%5B42%5D"
);
}
CAF_TEST
(
empty
components
)
{
...
...
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