Arriba

 view release on metacpan or  search on metacpan

lib/Arriba/Connection/SPDY.pm  view on Meta::CPAN

package Arriba::Connection::SPDY;

use warnings;
use strict;

use HTTP::Date;
use HTTP::Status qw(status_message);
use IO::Socket qw(:crlf);
use Net::SPDY::Session;
use Plack::Util;

use Arriba::Request;

use base 'Arriba::Connection';

# The current version of Net::SPDY::Session has some debugging code in the
# process_frame method, which breaks things. Until that gets fixed, we'll use
# our own version of this method.
{
    ## no critic
    no strict 'refs';
    no warnings 'redefine';
    *{"Net::SPDY::Session::process_frame"} = sub {
        my $self = shift;

        my %frame = $self->{framer}->read_frame ();
        return () unless %frame;

        if (not $frame{control}) {
            #warn 'Not implemented: Data frame received';
            return %frame;
        }

        if ($frame{type} == Net::SPDY::Framer::SYN_STREAM) {
        } elsif ($frame{type} == Net::SPDY::Framer::SETTINGS) {
            $self->got_settings (%frame);
        } elsif ($frame{type} == Net::SPDY::Framer::PING) {
            $self->{framer}->write_ping (
                flags => 0,
                id => $frame{id},
            );
        } elsif ($frame{type} == Net::SPDY::Framer::GOAWAY) {
            $self->close (0);
        } elsif ($frame{type} == Net::SPDY::Framer::HEADERS) {
            # We should remember values gotten here for stream
            #warn 'Not implemented: Got headers frame'
        } elsif ($frame{type} == Net::SPDY::Framer::WINDOW_UPDATE) {
        } else {
            die 'Unknown frame type '.$frame{type};
        }

        return %frame;
    };
}

sub new {
    my $class = shift;
    my $self = $class->SUPER::new(@_);

    $self->{_spdy} = {
        session => Net::SPDY::Session->new($self->{client}),
        streams => {},
    };

    return $self;
}

sub read_request {
    my $self = shift;

    my $session = $self->{_spdy}->{session};
    my $streams = $self->{_spdy}->{streams};

    my $req;

    while (my %frame = $session->process_frame) {
        if (exists $frame{type}) {
            if ($frame{type} == Net::SPDY::Framer::SYN_STREAM) {
                # Request initiated
                $req = Arriba::Request->new($self);
                $req->{_spdy} = {
                    # Keep track of this request's stream ID
                    stream_id => $frame{stream_id},
                    # Save a reference to the frame that initiated this request
                    frame => \%frame,
                };

                $streams->{$frame{stream_id}} = { req => $req };

                my %frame_headers = @{$frame{headers}};
                my @http_headers = @{$frame{headers}};

                my $headers = '';
                # Construct the HTTP request line
                $headers .= $frame_headers{':method'}  . ' ' .
                    $frame_headers{':path'} . ' ' .
                    $frame_headers{':version'} . $CRLF;

                $req->{scheme} = $frame_headers{':scheme'};

                if ($frame_headers{':host'}) {
                    $headers .= 'host: ' . $frame_headers{':host'} . $CRLF;
                }
                
                for (my $i = 0; $i < $#http_headers; $i += 2) {
                    if ($http_headers[$i] !~ /^:/) {
                        $headers .= "$http_headers[$i]: $http_headers[$i+1]$CRLF";
                    }
                }

                $headers .= $CRLF;

                $req->{headers} = $headers;
            }
            else {
                # FIXME: Other cases
                next;
            }



( run in 1.608 second using v1.01-cache-2.11-cpan-ceb78f64989 )