Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
pistache
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
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
Libraries
pistache
Commits
a32b5db1
Unverified
Commit
a32b5db1
authored
Dec 25, 2018
by
Dennis Jenkins
Committed by
GitHub
Dec 25, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #366 from hydratim/IPv6
Added IPv6 support
parents
385c78fb
84da2c7d
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
247 additions
and
44 deletions
+247
-44
include/pistache/http.h
include/pistache/http.h
+1
-8
include/pistache/net.h
include/pistache/net.h
+23
-0
src/common/http_header.cc
src/common/http_header.cc
+43
-7
src/common/net.cc
src/common/net.cc
+128
-24
src/server/listener.cc
src/server/listener.cc
+1
-1
tests/CMakeLists.txt
tests/CMakeLists.txt
+1
-1
tests/headers_test.cc
tests/headers_test.cc
+16
-0
tests/net_test.cc
tests/net_test.cc
+34
-3
No files found.
include/pistache/http.h
View file @
a32b5db1
...
...
@@ -815,15 +815,8 @@ namespace helpers
{
inline
Address
httpAddr
(
const
StringView
&
view
)
{
auto
const
str
=
view
.
toString
();
auto
const
pos
=
str
.
find
(
':'
);
if
(
pos
==
std
::
string
::
npos
)
{
return
Address
(
std
::
move
(
str
),
HTTP_STANDARD_PORT
);
return
Address
(
str
);
}
auto
const
host
=
str
.
substr
(
0
,
pos
);
auto
const
port
=
std
::
stoi
(
str
.
substr
(
pos
+
1
));
return
Address
(
std
::
move
(
host
),
port
);
}
}
// namespace helpers
}
// namespace Http
}
// namespace Pistache
include/pistache/net.h
View file @
a32b5db1
...
...
@@ -53,6 +53,7 @@ public:
static
Ipv4
any
();
std
::
string
toString
()
const
;
void
toNetwork
(
in_addr_t
*
)
const
;
private:
uint8_t
a
;
...
...
@@ -61,6 +62,25 @@ private:
uint8_t
d
;
};
class
Ipv6
{
public:
Ipv6
(
uint16_t
a
,
uint16_t
b
,
uint16_t
c
,
uint16_t
d
,
uint16_t
e
,
uint16_t
f
,
uint16_t
g
,
uint16_t
h
);
static
Ipv6
any
();
std
::
string
toString
()
const
;
void
toNetwork
(
in6_addr
*
)
const
;
private:
uint16_t
a
;
uint16_t
b
;
uint16_t
c
;
uint16_t
d
;
uint16_t
e
;
uint16_t
f
;
uint16_t
g
;
uint16_t
h
;
};
class
Address
{
public:
Address
();
...
...
@@ -68,6 +88,7 @@ public:
Address
(
std
::
string
addr
);
Address
(
const
char
*
addr
);
Address
(
Ipv4
ip
,
Port
port
);
Address
(
Ipv6
ip
,
Port
port
);
Address
(
const
Address
&
other
)
=
default
;
Address
(
Address
&&
other
)
=
default
;
...
...
@@ -79,11 +100,13 @@ public:
std
::
string
host
()
const
;
Port
port
()
const
;
int
family
()
const
;
private:
void
init
(
const
std
::
string
&
addr
);
std
::
string
host_
;
Port
port_
;
int
family_
=
AF_INET
;
};
class
Error
:
public
std
::
runtime_error
{
...
...
src/common/http_header.cc
View file @
a32b5db1
...
...
@@ -6,6 +6,7 @@
#include <stdexcept>
#include <iterator>
#include <limits>
#include <cstring>
#include <iostream>
...
...
@@ -13,6 +14,7 @@
#include <pistache/common.h>
#include <pistache/http.h>
#include <pistache/stream.h>
#include <arpa/inet.h>
using
namespace
std
;
...
...
@@ -340,15 +342,49 @@ Host::Host(const std::string& data)
void
Host
::
parse
(
const
std
::
string
&
data
)
{
auto
pos
=
data
.
find
(
':'
);
unsigned
long
pos
=
data
.
find
(
']'
);
unsigned
long
s_pos
=
data
.
find
(
'['
);
if
(
pos
!=
std
::
string
::
npos
&&
s_pos
!=
std
::
string
::
npos
)
{
//IPv6 address
host_
=
data
.
substr
(
s_pos
,
pos
+
1
);
try
{
in6_addr
addr6
;
char
buff6
[
INET6_ADDRSTRLEN
+
1
];
memcpy
(
buff6
,
host_
.
c_str
(),
INET6_ADDRSTRLEN
);
inet_pton
(
AF_INET6
,
buff6
,
&
(
addr6
.
s6_addr16
));
}
catch
(
std
::
runtime_error
)
{
throw
std
::
invalid_argument
(
"Invalid IPv6 address"
);
}
pos
++
;
}
else
{
//IPv4 address
pos
=
data
.
find
(
':'
);
if
(
pos
==
std
::
string
::
npos
)
{
host_
=
data
;
port_
=
HTTP_STANDARD_PORT
;
}
host_
=
data
.
substr
(
0
,
pos
);
if
(
host_
==
"*"
)
{
host_
=
"0.0.0.0"
;
}
try
{
in_addr
addr
;
char
buff
[
INET_ADDRSTRLEN
+
1
];
memcpy
(
buff
,
host_
.
c_str
(),
INET_ADDRSTRLEN
);
inet_pton
(
AF_INET
,
buff
,
&
(
addr
));
}
catch
(
std
::
runtime_error
)
{
throw
std
::
invalid_argument
(
"Invalid IPv4 address"
);
}
}
char
*
end
;
const
std
::
string
portPart
=
data
.
substr
(
pos
+
1
);
long
port
;
if
(
pos
!=
std
::
string
::
npos
)
{
std
::
string
h
=
data
.
substr
(
0
,
pos
);
int16_t
p
=
std
::
stoi
(
data
.
substr
(
pos
+
1
));
host_
=
h
;
port_
=
p
;
port
=
strtol
(
portPart
.
c_str
(),
&
end
,
10
);
if
(
port
<
std
::
numeric_limits
<
uint16_t
>::
min
()
||
port
>
std
::
numeric_limits
<
uint16_t
>::
max
())
throw
std
::
invalid_argument
(
"Invalid port"
);
port_
=
static_cast
<
uint16_t
>
(
port
);
}
else
{
host_
=
data
;
port_
=
HTTP_STANDARD_PORT
;
}
}
...
...
src/common/net.cc
View file @
a32b5db1
...
...
@@ -52,12 +52,71 @@ Ipv4::any() {
std
::
string
Ipv4
::
toString
()
const
{
static
constexpr
size_t
MaxSize
=
sizeof
(
"255"
)
*
4
+
3
+
1
;
/* 4 * 255 + 3 * dot + \0 */
// Use the built-in ipv4 string length from arpa/inet.h
char
buff
[
INET_ADDRSTRLEN
+
1
];
in_addr_t
addr
;
toNetwork
(
&
addr
);
// Convert the network format address into display format
inet_ntop
(
AF_INET
,
&
addr
,
buff
,
INET_ADDRSTRLEN
);
return
std
::
string
(
buff
);
}
char
buff
[
MaxSize
];
snprintf
(
buff
,
MaxSize
,
"%d.%d.%d.%d"
,
a
,
b
,
c
,
d
);
void
Ipv4
::
toNetwork
(
in_addr_t
*
addr
)
const
{
// Bitshift the bytes into an in_addr_t (a single 32bit unsigned int);
*
addr
=
htonl
(
(
uint32_t
)(
a
<<
24
)
|
(
uint32_t
)(
b
<<
16
)
|
(
uint32_t
)(
c
<<
8
)
|
(
uint32_t
)
d
);;
}
return
std
::
string
(
buff
);
Ipv6
::
Ipv6
(
uint16_t
a
,
uint16_t
b
,
uint16_t
c
,
uint16_t
d
,
uint16_t
e
,
uint16_t
f
,
uint16_t
g
,
uint16_t
h
)
:
a
(
a
)
,
b
(
b
)
,
c
(
c
)
,
d
(
d
)
,
e
(
e
)
,
f
(
f
)
,
g
(
g
)
,
h
(
h
)
{
}
Ipv6
Ipv6
::
any
()
{
return
Ipv6
(
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
);
}
std
::
string
Ipv6
::
toString
()
const
{
// Use the built-in ipv6 string length from arpa/inet.h
char
buff6
[
INET6_ADDRSTRLEN
+
1
];
in6_addr
addr
;
toNetwork
(
&
addr
);
inet_ntop
(
AF_INET6
,
&
addr
,
buff6
,
INET6_ADDRSTRLEN
);
return
std
::
string
(
"["
)
+
std
::
string
(
buff6
)
+
std
::
string
(
"]"
);
}
void
Ipv6
::
toNetwork
(
in6_addr
*
addr6
)
const
{
uint16_t
temp_ip6
[
8
]
=
{
a
,
b
,
c
,
d
,
e
,
f
,
g
,
h
};
uint16_t
remap_ip6
[
8
]
=
{
0
};
uint16_t
x
,
y
;
// If native endianness is little-endian swap the bytes, otherwise just copy them into the new array
if
(
htonl
(
1
)
!=
1
)
{
for
(
uint16_t
i
=
0
;
i
<
8
;
i
++
)
{
x
=
temp_ip6
[
i
];
y
=
htons
(
x
);
remap_ip6
[
i
]
=
y
;
}
}
else
{
memcpy
(
remap_ip6
,
temp_ip6
,
16
);
}
// Copy the bytes into the in6_addr struct
memcpy
(
addr6
->
s6_addr16
,
remap_ip6
,
16
);
}
Address
::
Address
()
...
...
@@ -66,9 +125,12 @@ Address::Address()
{
}
Address
::
Address
(
std
::
string
host
,
Port
port
)
:
host_
(
std
::
move
(
host
))
,
port_
(
port
)
{
}
{
std
::
string
addr
=
host
;
addr
.
append
(
":"
);
addr
.
append
(
port
.
toString
());
init
(
std
::
move
(
addr
));
}
Address
::
Address
(
std
::
string
addr
)
...
...
@@ -84,18 +146,33 @@ Address::Address(const char* addr)
Address
::
Address
(
Ipv4
ip
,
Port
port
)
:
host_
(
ip
.
toString
())
,
port_
(
port
)
,
family_
(
AF_INET
)
{
}
Address
::
Address
(
Ipv6
ip
,
Port
port
)
:
host_
(
ip
.
toString
())
,
port_
(
port
)
,
family_
(
AF_INET6
)
{
}
Address
Address
::
fromUnix
(
struct
sockaddr
*
addr
)
{
struct
sockaddr_in
*
in_addr
=
reinterpret_cast
<
struct
sockaddr_in
*>
(
addr
);
char
*
host
=
inet_ntoa
(
in_addr
->
sin_addr
);
assert
(
addr
);
int
port
=
ntohs
(
in_addr
->
sin_port
);
return
Address
(
host
,
port
);
if
(
addr
->
sa_family
==
AF_INET
)
{
struct
sockaddr_in
*
in_addr
=
reinterpret_cast
<
struct
sockaddr_in
*>
(
addr
);
char
host
[
INET_ADDRSTRLEN
+
1
];
inet_ntop
(
AF_INET
,
&
(
in_addr
->
sin_addr
),
host
,
INET_ADDRSTRLEN
);
int
port
=
ntohs
(
in_addr
->
sin_port
);
assert
(
addr
);
return
Address
(
host
,
port
);
}
else
if
(
addr
->
sa_family
==
AF_INET6
)
{
struct
sockaddr_in6
*
in_addr
=
reinterpret_cast
<
struct
sockaddr_in6
*>
(
addr
);
char
host
[
INET6_ADDRSTRLEN
+
1
];
inet_ntop
(
AF_INET6
,
&
(
in_addr
->
sin6_addr
),
host
,
INET6_ADDRSTRLEN
);
int
port
=
ntohs
(
in_addr
->
sin6_port
);
assert
(
addr
);
return
Address
(
host
,
port
);
}
throw
Error
(
"Not an IP socket"
);
}
std
::
string
...
...
@@ -108,18 +185,45 @@ Address::port() const {
return
port_
;
}
int
Address
::
family
()
const
{
return
family_
;
}
void
Address
::
init
(
const
std
::
string
&
addr
)
{
const
auto
pos
=
addr
.
find
(
':'
);
if
(
pos
==
std
::
string
::
npos
)
throw
std
::
invalid_argument
(
"Invalid address"
);
host_
=
addr
.
substr
(
0
,
pos
);
if
(
host_
==
"*"
)
{
host_
=
"0.0.0.0"
;
unsigned
long
pos
=
addr
.
find
(
']'
);
unsigned
long
s_pos
=
addr
.
find
(
'['
);
if
(
pos
!=
std
::
string
::
npos
&&
s_pos
!=
std
::
string
::
npos
)
{
//IPv6 address
host_
=
addr
.
substr
(
s_pos
,
pos
+
1
);
try
{
in6_addr
addr6
;
char
buff6
[
INET6_ADDRSTRLEN
+
1
];
memcpy
(
buff6
,
host_
.
c_str
(),
INET6_ADDRSTRLEN
);
inet_pton
(
AF_INET6
,
buff6
,
&
(
addr6
.
s6_addr16
));
}
catch
(
std
::
runtime_error
)
{
throw
std
::
invalid_argument
(
"Invalid IPv6 address"
);
}
pos
++
;
}
else
{
//IPv4 address
pos
=
addr
.
find
(
':'
);
if
(
pos
==
std
::
string
::
npos
)
throw
std
::
invalid_argument
(
"Invalid address"
);
host_
=
addr
.
substr
(
0
,
pos
);
if
(
host_
==
"*"
)
{
host_
=
"0.0.0.0"
;
}
try
{
in_addr
addr
;
char
buff
[
INET_ADDRSTRLEN
+
1
];
memcpy
(
buff
,
host_
.
c_str
(),
INET6_ADDRSTRLEN
);
inet_pton
(
AF_INET
,
buff
,
&
(
addr
));
}
catch
(
std
::
runtime_error
)
{
throw
std
::
invalid_argument
(
"Invalid IPv4 address"
);
}
}
char
*
end
;
const
std
::
string
portPart
=
addr
.
substr
(
pos
+
1
);
if
(
portPart
.
empty
())
...
...
src/server/listener.cc
View file @
a32b5db1
...
...
@@ -157,7 +157,7 @@ Listener::bind(const Address& address) {
addr_
=
address
;
struct
addrinfo
hints
;
hints
.
ai_family
=
AF_INET
;
hints
.
ai_family
=
address
.
family
()
;
hints
.
ai_socktype
=
SOCK_STREAM
;
hints
.
ai_flags
=
AI_PASSIVE
;
hints
.
ai_protocol
=
0
;
...
...
tests/CMakeLists.txt
View file @
a32b5db1
...
...
@@ -3,7 +3,7 @@ function(pistache_test test_name)
set
(
TEST_SOURCE
${
test_name
}
.cc
)
add_executable
(
${
TEST_EXECUTABLE
}
${
TEST_SOURCE
}
)
target_link_libraries
(
${
TEST_EXECUTABLE
}
gtest gtest_main pistache curl
)
target_link_libraries
(
${
TEST_EXECUTABLE
}
gtest gtest_main pistache curl
pthread
)
add_test
(
${
test_name
}
${
TEST_EXECUTABLE
}
)
endfunction
()
...
...
tests/headers_test.cc
View file @
a32b5db1
...
...
@@ -257,6 +257,22 @@ TEST(headers_test, host) {
host
.
parse
(
"localhost:8080"
);
ASSERT_EQ
(
host
.
host
(),
"localhost"
);
ASSERT_EQ
(
host
.
port
(),
8080
);
/* Due to an error in GLIBC these tests don't fail as expected, further research needed */
// ASSERT_THROW( host.parse("256.256.256.256:8080");, std::invalid_argument);
// ASSERT_THROW( host.parse("1.0.0.256:8080");, std::invalid_argument);
host
.
parse
(
"[::1]:8080"
);
ASSERT_EQ
(
host
.
host
(),
"[::1]"
);
ASSERT_EQ
(
host
.
port
(),
8080
);
host
.
parse
(
"[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080"
);
ASSERT_EQ
(
host
.
host
(),
"[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]"
);
ASSERT_EQ
(
host
.
port
(),
8080
);
/* Due to an error in GLIBC these tests don't fail as expected, further research needed */
// ASSERT_THROW( host.parse("[GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG]:8080");, std::invalid_argument);
// ASSERT_THROW( host.parse("[::GGGG]:8080");, std::invalid_argument);
}
TEST
(
headers_test
,
user_agent
)
{
...
...
tests/net_test.cc
View file @
a32b5db1
...
...
@@ -46,8 +46,33 @@ TEST(net_test, address_creation)
ASSERT_EQ
(
address4
.
port
(),
8080
);
Address
address5
(
"*:8080"
);
ASSERT_EQ
(
address4
.
host
(),
"0.0.0.0"
);
ASSERT_EQ
(
address4
.
port
(),
8080
);
ASSERT_EQ
(
address5
.
host
(),
"0.0.0.0"
);
ASSERT_EQ
(
address5
.
port
(),
8080
);
Address
address6
(
"[::1]:8080"
);
ASSERT_EQ
(
address6
.
host
(),
"[::1]"
);
ASSERT_EQ
(
address6
.
port
(),
8080
);
std
::
string
addr2
=
"[::1]"
;
Address
address7
(
addr2
,
Port
(
8080
));
ASSERT_EQ
(
address7
.
host
(),
"[::1]"
);
ASSERT_EQ
(
address7
.
port
(),
8080
);
Address
address8
(
Ipv6
(
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
),
Port
(
8080
));
ASSERT_EQ
(
address8
.
host
(),
"[::1]"
);
ASSERT_EQ
(
address8
.
port
(),
8080
);
Address
address9
(
Ipv6
::
any
(),
Port
(
8080
));
ASSERT_EQ
(
address9
.
host
(),
"[::]"
);
ASSERT_EQ
(
address9
.
port
(),
8080
);
Address
address10
(
"[::]:8080"
);
ASSERT_EQ
(
address10
.
host
(),
"[::]"
);
ASSERT_EQ
(
address10
.
port
(),
8080
);
Address
address11
(
"[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080"
);
ASSERT_EQ
(
address11
.
host
(),
"[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]"
);
ASSERT_EQ
(
address11
.
port
(),
8080
);
}
TEST
(
net_test
,
invalid_address
)
...
...
@@ -56,4 +81,10 @@ TEST(net_test, invalid_address)
ASSERT_THROW
(
Address
(
"127.0.0.1:9999999"
),
std
::
invalid_argument
);
ASSERT_THROW
(
Address
(
"127.0.0.1:"
),
std
::
invalid_argument
);
ASSERT_THROW
(
Address
(
"127.0.0.1:-10"
),
std
::
invalid_argument
);
}
\ No newline at end of file
/* Due to an error in GLIBC these tests don't fail as expected, further research needed */
// ASSERT_THROW(Address("[GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG]:8080");, std::invalid_argument);
// ASSERT_THROW(Address("[::GGGG]:8080");, std::invalid_argument);
// ASSERT_THROW(Address("256.256.256.256:8080");, std::invalid_argument);
// ASSERT_THROW(Address("1.0.0.256:8080");, std::invalid_argument);
}
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