in reply to Is wise to use HTTP::Proxy to enforce correct Content-Range responses?
Following this story.
As Yum people don't want to modify it and my network admin the gateway either, I tried writing this little piece of crap:
And a simple untested test case.{ 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 reque +st. # # 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 ret +urn; 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 ), $$datar +ef ); $$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; }
#!/usr/bin/perl use strict; use HTTP::Proxy::ContentRange; my $Superproxy = "http://you-upstream-proxy-here"; my $Proxy = HTTP::Proxy::ContentRange->new(); $Proxy->init(); { my $ua = $Proxy->agent(); $ua->proxy(['http', 'ftp'], $Superproxy ); $ua->protocols_allowed( ['http', 'ftp'] ); } $proxy->start();
Actually it works pretty well when the file size isn't big enough to cause a timeout while Yum waits for the end of transmission, as I keep receiving and discarding data from upstream server.
What I need is stop the communication with the client, i.e. yum, when the end of requested range if found.
Something like issuing some sort of EOF on the client socket, close it and close also the LWP::UserAgent upstream connection.
Anyway, I begun felling that subclass a HTTP::Proxy::BodyFilter isn't the way it will work, at least not in a beautiful way. Maybe subclass HTTP::Proxy?
I keep asking: is this the better approach to the original problem?
I'm willing to receive critics about my code style, and idiomatic or semantic tips too.
Thank you very much.
|
|---|