Net-WebSocket

 view release on metacpan or  search on metacpan

lib/Net/WebSocket/Frame.pm  view on Meta::CPAN

package Net::WebSocket::Frame;

=encoding utf-8

=head1 NAME

Net::WebSocket::Frame

=head1 SYNOPSIS

    #Never instantiate Net::WebSocket::Frame directly;
    #always call new() on a subclass:
    my $frame = Net::WebSocket::Frame::text->new(
        fin => 0,                   #to start a fragmented message
        rsv => 0b11,                #RSV2 and RSV3 are on
        mask => "\x01\x02\x03\x04   #clients MUST include; servers MUST NOT
        payload => \'Woot!',
    );

    $frame->get_fin();
    $frame->get_mask_bytes();
    $frame->get_payload();

    $frame->set_rsv();
    $frame->get_rsv();

    $frame->to_bytes();     #for sending over the wire

=head1 DESCRIPTION

This is the base class for all frame objects. The interface as described
above should be fairly straightforward.

=head1 EXPERIMENTAL: CUSTOM FRAME CLASSES

You can have custom frame classes, e.g., to support WebSocket extensions that
use custom frame opcodes. RFC 6455 allocates opcodes 3-7 for data frames and
11-15 (0xb - 0xf) for control frames.

The best way to do this is to subclass either
L<Net::WebSocket::Base::DataFrame> or L<Net::WebSocket::Base::ControlFrame>,
depending on what kind of frame you’re dealing with.

An example of such a class is below:

    package My::Custom::Frame::booya;

    use strict;
    use warnings;

    use parent qw( Net::WebSocket::Base::DataFrame );

    use constant get_opcode => 3;

    use constant get_type => 'booya';

Note that L<Net::WebSocket::Parser> still won’t know how to handle such a
custom frame, so if you intend to receive custom frames as part of messages,
you’ll also need to create a custom base class of this class, then also
subclass L<Net::WebSocket::Parser>. You may additionally want to subclass
L<Net::WebSocket::Streamer::Server> (or -C<::Client>) if you do streaming.

B<NOTE: THIS IS LARGELY UNTESTED.> I’m not familiar with any application that
actually requires this feature. The C<permessage-deflate> extension seems to
be the only one that has much widespread web browser support.

=cut

use strict;
use warnings;

use parent qw(
    Net::WebSocket::Base::Typed
);

use Net::WebSocket::Constants ();
use Net::WebSocket::Mask ();
use Net::WebSocket::X ();

use constant {
    FIRST2 => 0,
    LEN_LEN => 1,
    MASK => 2,
    PAYLOAD => 3,

    _RSV1 => chr(4 << 4),
    _RSV2 => chr(2 << 4),
    _RSV3 => chr(1 << 4),
};

#fin, rsv, mask, payload
#rsv is a bitmask of the three values, with RSV1 as MOST significant bit.
#So, represent RSV1 and RSV2 being on via 0b110 (= 4 + 2 = 6)
sub new {
    my $class = shift;

    my ( $fin, $rsv, $mask, $payload_sr );

    #We loop through like this so that we can get a nice
    #syntax for “payload” without copying the string.
    #This logic should be equivalent to a hash.
    while (@_) {
        my $key = shift;

        #“payload_sr” (as a named argument) is legacy
        if ($key eq 'payload' || $key eq 'payload_sr') {
            if (!ref $_[0]) {
                if (defined $_[0]) {
                    $payload_sr = \shift;
                }
                else {
                    shift;
                    next;
                }
            }
            elsif ('SCALAR' eq ref $_[0]) {
                $payload_sr = shift;
            }
            else {
                die Net::WebSocket::X->create('BadArg', $key => shift, 'Must be a scalar or SCALAR reference.');
            }



( run in 0.571 second using v1.01-cache-2.11-cpan-39bf76dae61 )