{ package HTTP::Proxy::ContentRange::Header; # First of all, detect which responses must be handled by # this proxy. # i.e All the 200 OK responses issued for a Content-Ranged request. # # The HTTP specs talk about Range Header too. use base qw(HTTP::Proxy::HeaderFilter); use strict; sub filter() { my ( $self, $headers, $message ) = @_; my $s = $self->proxy->stash(); my $range; if ( $message->isa('HTTP::Response') and $message->code == 200 and ( $range = $message->request->header('Content-Range') or $range = $message->request->header('Range') ) ) { #Let's fix that nasty behaviour! ;-) #First we turn this in a Partial Content response... $message->code(206); $message->message("Partial Content"); $message->header( 'Content-Range' => $range ); # Zero-based. $range =~ /(\d+)-(\d+)/; $message->header( 'Content-Length' => ( $2 - $1 ) + 1 ); #...And mark this response for body processing using #the stash to pass this information to body filter. $s->{ $message->request->uri } = { range => $range, }; } } 1; } { package HTTP::Proxy::ContentRange::Body; use base qw(HTTP::Proxy::BodyFilter); use Set::Infinite; use strict; sub filter { my ( $self, $dataref, $message, $procotol, $buffer ) = @_; return if $$dataref eq ''; my $s = $self->proxy->stash->{ $message->request->uri } or return; my $seek = $s->{'seek'} || 0; #The next seek will be... $s->{'seek'} = $seek + length $$dataref; $s->{'range'} =~ /(\d+)-(\d+)/; #The content range I want, relative to this chunk. my $range = Set::Infinite->new( $1 - $seek, $2 - $seek ); #This chunk. my $chunk = Set::Infinite->new( 0, length($$dataref) - 1 ); #Intersection beetween them is data we want. if ( $range->intersects($chunk) ) { my $i = $range->intersection($chunk); my $data = unpack( "x" . $i->min . " a" . ( $i->size + 1 ), $$dataref ); $$dataref = $data; } else { $$dataref = ""; if ( $range->max < 0 ) { #In this case, we've already got all data we want, #hence the negative position of $range relative to #this chunk. ### ### XXX: HERE IT MUST SOMEHOW END THE CONVERSATION. ### #I tried: #print { $self->proxy->client_connection() } "\012\015"; #close { $self->proxy->client_connection() }; #But this didn't worked out. } } } 1; } { package HTTP::Proxy::ContentRange; use base qw(HTTP::Proxy); sub new { my $class = shift; my $self = bless $class->SUPER::new(@_); $self->push_filter( scheme => 'http', mime => '*/*', response => HTTP::Proxy::ContentRange::Header->new(), response => HTTP::Proxy::ContentRange::Body->new(), ); return $self; } 1; }