Skip to content

Commit

Permalink
added WebSocket protocol support to Mojo::UserAgent::Transactor
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed May 23, 2013
1 parent 8c97356 commit c8ddc63
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 20 deletions.
1 change: 1 addition & 0 deletions Changes
@@ -1,5 +1,6 @@

4.04 2013-05-23
- Added WebSocket protocol support to Mojo::UserAgent::Transactor.

4.03 2013-05-21
- Fixed redirect support in get command.
Expand Down
6 changes: 2 additions & 4 deletions lib/Mojo/Transaction/WebSocket.pm
Expand Up @@ -91,10 +91,8 @@ sub client_handshake {
my $self = shift;

my $headers = $self->req->headers;
$headers->upgrade('websocket') unless $headers->upgrade;
$headers->connection('Upgrade') unless $headers->connection;
$headers->sec_websocket_protocol('mojo')
unless $headers->sec_websocket_protocol;
$headers->upgrade('websocket') unless $headers->upgrade;
$headers->connection('Upgrade') unless $headers->connection;
$headers->sec_websocket_version(13) unless $headers->sec_websocket_version;

# Generate WebSocket challenge
Expand Down
3 changes: 2 additions & 1 deletion lib/Mojo/UserAgent.pm
Expand Up @@ -971,7 +971,8 @@ non-blocking.
=head2 websocket
$ua->websocket('ws://localhost:3000' => sub {...});
$ua->websocket('ws://localhost:3000' => {DNT => 1} => sub {...});
$ua->websocket(
'ws://localhost:3000' => {DNT => 1} => ['proto'] => sub {...});
Open a non-blocking WebSocket connection with transparent handshake, takes the
same arguments as L<Mojo::UserAgent::Transactor/"websocket">. The callback
Expand Down
9 changes: 6 additions & 3 deletions lib/Mojo/UserAgent/Transactor.pm
Expand Up @@ -134,8 +134,11 @@ sub websocket {
my $self = shift;

# New WebSocket transaction
my $tx = $self->tx(GET => @_);
my $url = $tx->req->url;
my $protos = ref $_[-1] eq 'ARRAY' ? pop : [];
my $tx = $self->tx(GET => @_);
my $req = $tx->req;
$req->headers->sec_websocket_protocol(join ', ', @$protos) if @$protos;
my $url = $req->url;
my $proto = $url->protocol;
$url->scheme($proto eq 'wss' ? 'https' : 'http') if $proto;

Expand Down Expand Up @@ -410,7 +413,7 @@ handshake if possible.
=head2 websocket
my $tx = $t->websocket('ws://localhost:3000');
my $tx = $t->websocket('ws://localhost:3000' => {DNT => 1});
my $tx = $t->websocket('ws://localhost:3000' => {DNT => 1} => ['proto']);
Versatile L<Mojo::Transaction::HTTP> transaction builder for WebSocket
handshake requests.
Expand Down
2 changes: 1 addition & 1 deletion lib/Test/Mojo.pm
Expand Up @@ -876,7 +876,7 @@ Opposite of C<text_like>.
=head2 websocket_ok
$t = $t->websocket_ok('/echo');
$t = $t->websocket_ok('/echo' => {DNT => 1});
$t = $t->websocket_ok('/echo' => {DNT => 1} => ['proto']);
Open a WebSocket connection with transparent handshake, takes the same
arguments as L<Mojo::UserAgent/"websocket">, except for the callback.
Expand Down
37 changes: 32 additions & 5 deletions t/mojo/transactor.t
Expand Up @@ -409,8 +409,8 @@ is $tx->req->url->to_abs, 'http://127.0.0.1:3000/echo', 'right URL';
is $tx->req->method, 'GET', 'right method';
is $tx->req->headers->connection, 'Upgrade', 'right "Connection" value';
ok $tx->req->headers->sec_websocket_key, 'has "Sec-WebSocket-Key" value';
ok $tx->req->headers->sec_websocket_protocol,
'has "Sec-WebSocket-Protocol" value';
ok !$tx->req->headers->sec_websocket_protocol,
'no "Sec-WebSocket-Protocol" header';
ok $tx->req->headers->sec_websocket_version,
'has "Sec-WebSocket-Version" value';
is $tx->req->headers->upgrade, 'websocket', 'right "Upgrade" value';
Expand All @@ -423,11 +423,38 @@ ok $tx->is_websocket, 'is a WebSocket';
$tx = $t->websocket('wss://127.0.0.1:3000/echo' => {Expect => 'foo'});
is $tx->req->url->to_abs, 'https://127.0.0.1:3000/echo', 'right URL';
is $tx->req->method, 'GET', 'right method';
is $tx->req->headers->expect, 'foo', 'right "Upgrade" value';
is $tx->req->headers->expect, 'foo', 'right "Expect" value';
is $tx->req->headers->connection, 'Upgrade', 'right "Connection" value';
ok $tx->req->headers->sec_websocket_key, 'has "Sec-WebSocket-Key" value';
ok $tx->req->headers->sec_websocket_protocol,
'has "Sec-WebSocket-Protocol" value';
ok !$tx->req->headers->sec_websocket_protocol,
'no "Sec-WebSocket-Protocol" header';
ok $tx->req->headers->sec_websocket_version,
'has "Sec-WebSocket-Version" value';
is $tx->req->headers->upgrade, 'websocket', 'right "Upgrade" value';

# WebSocket handshake with protocol
$tx = $t->websocket('wss://127.0.0.1:3000/echo' => ['foo']);
is $tx->req->url->to_abs, 'https://127.0.0.1:3000/echo', 'right URL';
is $tx->req->method, 'GET', 'right method';
is $tx->req->headers->connection, 'Upgrade', 'right "Connection" value';
ok $tx->req->headers->sec_websocket_key, 'has "Sec-WebSocket-Key" value';
is $tx->req->headers->sec_websocket_protocol, 'foo',
'right "Sec-WebSocket-Protocol" value';
ok $tx->req->headers->sec_websocket_version,
'has "Sec-WebSocket-Version" value';
is $tx->req->headers->upgrade, 'websocket', 'right "Upgrade" value';

# WebSocket handshake with header and protocols
$tx = $t->websocket('wss://127.0.0.1:3000/echo' => {DNT => 1} =>
['v1.bar.example.com', 'foo', 'v2.baz.example.com']);
is $tx->req->url->to_abs, 'https://127.0.0.1:3000/echo', 'right URL';
is $tx->req->method, 'GET', 'right method';
is $tx->req->headers->dnt, '1', 'right "DNT" value';
is $tx->req->headers->connection, 'Upgrade', 'right "Connection" value';
ok $tx->req->headers->sec_websocket_key, 'has "Sec-WebSocket-Key" value';
is $tx->req->headers->sec_websocket_protocol,
'v1.bar.example.com, foo, v2.baz.example.com',
'right "Sec-WebSocket-Protocol" value';
ok $tx->req->headers->sec_websocket_version,
'has "Sec-WebSocket-Version" value';
is $tx->req->headers->upgrade, 'websocket', 'right "Upgrade" value';
Expand Down
14 changes: 8 additions & 6 deletions t/mojolicious/websocket_lite_app.t
Expand Up @@ -101,20 +101,22 @@ post {data => 'plain nested too!'};

my $t = Test::Mojo->new;

# Default protocol
$t->websocket_ok('/echo')->header_is('Sec-WebSocket-Protocol' => 'mojo')
->send_ok('hello')->message_ok('got a message')->message_is('echo: hello')
->finish_ok;
# Simple roundtrip
$t->websocket_ok('/echo')->send_ok('hello')->message_ok('got a message')
->message_is('echo: hello')->finish_ok;

# Multiple roundtrips
$t->websocket_ok('/echo')->send_ok('hello again')
->message_ok->message_is('echo: hello again')->send_ok('and one more time')
->message_ok->message_is('echo: and one more time')->finish_ok;

# Custom protocol
$t->websocket_ok('/echo', {'Sec-WebSocket-Protocol' => 'foo, bar, baz'})
# Custom header and protocols
$t->websocket_ok('/echo' => {DNT => 1} => ['foo', 'bar', 'baz'])
->header_is('Sec-WebSocket-Protocol' => 'foo')->send_ok('hello')
->message_ok->message_is('echo: hello')->finish_ok;
is $t->tx->req->headers->dnt, 1, 'right "DNT" value';
is $t->tx->req->headers->sec_websocket_protocol, 'foo, bar, baz',
'right "Sec-WebSocket-Protocol" value';

# Bytes
$t->websocket_ok('/echo')->send_ok({binary => 'bytes!'})
Expand Down

0 comments on commit c8ddc63

Please sign in to comment.