Skip to content
This repository was archived by the owner on Apr 30, 2021. It is now read-only.

Commit ea63865

Browse files
committed
Do not decode bytes unless frame is_text. Correctly handle error code and message in close frames.
1 parent 869bd29 commit ea63865

File tree

2 files changed

+22
-8
lines changed

2 files changed

+22
-8
lines changed

lib/Protocol/WebSocket/Client.pm

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use Protocol::WebSocket::URL;
88
use Protocol::WebSocket::Handshake::Client;
99
use Protocol::WebSocket::Frame;
1010

11+
use Encode ();
12+
1113
sub new {
1214
my $class = shift;
1315
$class = ref $class if ref $class;
@@ -103,9 +105,15 @@ sub read {
103105
while (defined (my $bytes = $frame_buffer->next)) {
104106
if ($frame_buffer->is_close) {
105107
# Remote WebSocket close (TCP socket may stay open for a bit)
106-
$self->disconnect if ($self->is_ready);
107-
# TODO: see message in disconnect() about error code / reason
108-
$self->{on_eof}->($self) if $self->{on_eof};
108+
# Decode the error code and message, if it exists
109+
my $code = length $bytes > 1 ? unpack('n', substr($bytes, 0, 2)) : undef;
110+
my $message = length $bytes > 3 ? Encode::decode('UTF-8', substr($bytes, 2)) : undef;
111+
112+
# Spec says to send our own close frame (and echo the errno.)
113+
$self->disconnect($code) if ($self->is_ready);
114+
115+
# Call user callback
116+
$self->{on_eof}->($self, $code, $message) if $self->{on_eof};
109117
} elsif ($frame_buffer->is_pong) {
110118
# Server responded to our ping.
111119
$self->{on_pong}->($self, $bytes) if $self->{on_pong};
@@ -162,11 +170,13 @@ sub connect {
162170
# also sets state to -1 when called
163171
sub disconnect {
164172
my $self = shift;
173+
my ($code, $message) = @_;
174+
175+
my $buffer;
176+
if (defined $code) { $buffer = pack 'n', $code }
177+
if (defined $message) { $buffer .= Encode::encode('UTF-8', $message) }
165178

166-
# TODO: Spec states 'close' messages may contain a uint16 error code, and a utf-8 reason.
167-
# Clients are supposed to echo back the error code when receiving close from server.
168-
# For now, we just send an empty message.
169-
$self->write( $self->_build_frame(type => 'close', masked => 1) );
179+
$self->write( $self->_build_frame(type => 'close', masked => 1, buffer => $buffer) );
170180

171181
$self->{state} = -1;
172182

lib/Protocol/WebSocket/Frame.pm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@ sub next {
8484
my $bytes = $self->next_bytes;
8585
return unless defined $bytes;
8686

87-
return Encode::decode('UTF-8', $bytes);
87+
if ($self->is_text) {
88+
return Encode::decode('UTF-8', $bytes);
89+
} else {
90+
return $bytes;
91+
}
8892
}
8993

9094
sub fin {

0 commit comments

Comments
 (0)