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
1fee050e
Unverified
Commit
1fee050e
authored
Jun 13, 2023
by
Dominik Charousset
Committed by
GitHub
Jun 13, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1422
Fix handling of fragmented WebSocket frames
parents
1674ccd4
0082cea1
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
42 additions
and
7 deletions
+42
-7
CHANGELOG.md
CHANGELOG.md
+3
-0
libcaf_net/caf/detail/rfc6455.hpp
libcaf_net/caf/detail/rfc6455.hpp
+4
-1
libcaf_net/src/detail/rfc6455.cpp
libcaf_net/src/detail/rfc6455.cpp
+4
-3
libcaf_net/src/net/web_socket/framing.cpp
libcaf_net/src/net/web_socket/framing.cpp
+8
-1
libcaf_net/test/net/web_socket/server.cpp
libcaf_net/test/net/web_socket/server.cpp
+23
-2
No files found.
CHANGELOG.md
View file @
1fee050e
...
...
@@ -21,6 +21,9 @@ is based on [Keep a Changelog](https://keepachangelog.com).
-
Add missing initialization code for the new caf-net module when using the
`CAF_MAIN`
macro. This fixes the
`WSANOTINITIALISED`
error on Windows (#1409).
-
The WebSocket implementation now properly re-assembles fragmented frames.
Previously, a bug in the framing protocol implementation caused CAF to sever
the connection when encountering continuation frames (#1417).
### Added
...
...
libcaf_net/caf/detail/rfc6455.hpp
View file @
1fee050e
...
...
@@ -38,6 +38,8 @@ struct CAF_NET_EXPORT rfc6455 {
static
constexpr
uint8_t
pong
=
0x0A
;
static
constexpr
uint8_t
fin_flag
=
0x80
;
// -- utility functions ------------------------------------------------------
static
void
mask_data
(
uint32_t
key
,
span
<
char
>
data
);
...
...
@@ -51,7 +53,8 @@ struct CAF_NET_EXPORT rfc6455 {
byte_buffer
&
out
);
static
void
assemble_frame
(
uint8_t
opcode
,
uint32_t
mask_key
,
const_byte_span
data
,
byte_buffer
&
out
);
const_byte_span
data
,
byte_buffer
&
out
,
uint8_t
flags
=
fin_flag
);
static
ptrdiff_t
decode_header
(
const_byte_span
data
,
header
&
hdr
);
};
...
...
libcaf_net/src/detail/rfc6455.cpp
View file @
1fee050e
...
...
@@ -36,9 +36,10 @@ void rfc6455::assemble_frame(uint32_t mask_key, const_byte_span data,
}
void
rfc6455
::
assemble_frame
(
uint8_t
opcode
,
uint32_t
mask_key
,
const_byte_span
data
,
byte_buffer
&
out
)
{
// First 8 bits: FIN flag + opcode (we never fragment frames).
out
.
push_back
(
std
::
byte
{
static_cast
<
uint8_t
>
(
0x80
|
opcode
)});
const_byte_span
data
,
byte_buffer
&
out
,
uint8_t
flags
)
{
// First 8 bits: flags + opcode
out
.
push_back
(
std
::
byte
{
static_cast
<
uint8_t
>
(
flags
|
opcode
)});
// Mask flag + payload length (7 bits, 7+16 bits, or 7+64 bits)
auto
mask_bit
=
std
::
byte
{
static_cast
<
uint8_t
>
(
mask_key
==
0
?
0x00
:
0x80
)};
if
(
data
.
size
()
<
126
)
{
...
...
libcaf_net/src/net/web_socket/framing.cpp
View file @
1fee050e
...
...
@@ -82,7 +82,7 @@ ptrdiff_t framing::consume(byte_span buffer, byte_span) {
}
else
{
// End of fragmented input.
payload_buf_
.
insert
(
payload_buf_
.
end
(),
payload
.
begin
(),
payload
.
end
());
if
(
!
handle
(
hdr
.
opcode
,
payload_buf_
))
{
if
(
!
handle
(
opcode_
,
payload_buf_
))
{
return
-
1
;
}
opcode_
=
nil_code
;
...
...
@@ -90,6 +90,8 @@ ptrdiff_t framing::consume(byte_span buffer, byte_span) {
}
}
}
else
{
// The first frame must not be a continuation frame. Any frame that is not
// the first frame must be a continuation frame.
if
(
opcode_
==
nil_code
)
{
if
(
hdr
.
opcode
==
detail
::
rfc6455
::
continuation_frame
)
{
CAF_LOG_DEBUG
(
"received WebSocket continuation "
...
...
@@ -100,6 +102,11 @@ ptrdiff_t framing::consume(byte_span buffer, byte_span) {
return
-
1
;
}
opcode_
=
hdr
.
opcode
;
}
else
if
(
hdr
.
opcode
!=
detail
::
rfc6455
::
continuation_frame
)
{
CAF_LOG_DEBUG
(
"expected a continuation frame"
);
up_
->
abort
(
make_error
(
sec
::
protocol_error
,
//
"expected a continuation frame"
));
return
-
1
;
}
else
if
(
payload_buf_
.
size
()
+
payload_len
>
max_frame_size
)
{
// Reject assembled payloads that exceed max_frame_size.
CAF_LOG_DEBUG
(
"fragmented WebSocket payload exceeds maximum size"
);
...
...
libcaf_net/test/net/web_socket/server.cpp
View file @
1fee050e
...
...
@@ -89,11 +89,17 @@ struct fixture {
rng
.
seed
(
0xD3ADC0D3
);
}
void
rfc6455_append
(
uint8_t
opcode
,
const_byte_span
bytes
,
byte_buffer
&
out
)
{
void
rfc6455_append
(
uint8_t
opcode
,
const_byte_span
bytes
,
byte_buffer
&
out
,
uint8_t
flags
=
detail
::
rfc6455
::
fin_flag
)
{
byte_buffer
payload
{
bytes
.
begin
(),
bytes
.
end
()};
auto
key
=
static_cast
<
uint32_t
>
(
rng
());
detail
::
rfc6455
::
mask_data
(
key
,
payload
);
detail
::
rfc6455
::
assemble_frame
(
opcode
,
key
,
payload
,
out
);
detail
::
rfc6455
::
assemble_frame
(
opcode
,
key
,
payload
,
out
,
flags
);
}
void
rfc6455_append
(
uint8_t
opcode
,
std
::
string_view
text
,
byte_buffer
&
out
,
uint8_t
flags
=
detail
::
rfc6455
::
fin_flag
)
{
rfc6455_append
(
opcode
,
as_bytes
(
make_span
(
text
)),
out
,
flags
);
}
void
rfc6455_append
(
const_byte_span
bytes
,
byte_buffer
&
out
)
{
...
...
@@ -218,4 +224,19 @@ CAF_TEST(data may arrive later) {
CHECK_EQ
(
app
->
text_input
,
"Hello WebSocket!
\n
Bye WebSocket!
\n
"
);
}
CAF_TEST
(
data
may
arrive
fragmented
)
{
transport
->
push
(
opening_handshake
);
CHECK_EQ
(
transport
->
handle_input
(),
static_cast
<
ptrdiff_t
>
(
opening_handshake
.
size
()));
byte_buffer
buf
;
rfc6455_append
(
detail
::
rfc6455
::
text_frame
,
"Hello "
sv
,
buf
,
0
);
rfc6455_append
(
detail
::
rfc6455
::
continuation_frame
,
"WebSocket!
\n
"
sv
,
buf
);
rfc6455_append
(
detail
::
rfc6455
::
text_frame
,
"Bye "
sv
,
buf
,
0
);
rfc6455_append
(
detail
::
rfc6455
::
continuation_frame
,
"Web"
sv
,
buf
,
0
);
rfc6455_append
(
detail
::
rfc6455
::
continuation_frame
,
"Socket!
\n
"
sv
,
buf
);
transport
->
push
(
buf
);
CHECK_EQ
(
transport
->
handle_input
(),
static_cast
<
ptrdiff_t
>
(
buf
.
size
()));
CHECK_EQ
(
app
->
text_input
,
"Hello WebSocket!
\n
Bye WebSocket!
\n
"
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
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