use strict; use warnings; package Net::IMP::HTTP::Example::FlipImg; use base 'Net::IMP::HTTP::Request'; use fields ( 'ignore', # irrelevant content 'image', # collected octets for image ); use Net::IMP; # import IMP_ constants use Net::IMP::Debug; use Image::Magick; use constant MAX_SIZE => 2**16; sub RTYPES { ( IMP_PASS, IMP_REPLACE ) } sub new_analyzer { my ($factory,%args) = @_; my $self = $factory->SUPER::new_analyzer(%args); # request data do not matter $self->run_callback([ IMP_PASS,0,IMP_MAXOFFSET ]); return $self; } sub request_hdr {} sub request_body {} sub any_data {} sub response_hdr { my ($self,$hdr) = @_; my $ignore; # we only want selected image/ content types and not too big debug("header=$hdr"); my ($ct) = $hdr =~m{\nContent-type:[ \t]*([^\s;]+)}i; my ($clen) = $hdr =~m{\nContent-length:[ \t]*(\d+)}i; my ($code) = $hdr =~m{\AHTTP/1\.[01][ \t]+(\d+)}; if ( $code != 200 ) { debug("will not rotate code=$code"); $ignore++; } elsif ( ! $ct or $ct !~m{^image/(png|gif|jpeg)$} ) { debug("will not rotate content type $ct"); $ignore++; } elsif ( $clen and $clen > MAX_SIZE ) { debug("image is too big: $clen" ); $ignore++; } if ( $ignore ) { $self->run_callback([ IMP_PASS,1,IMP_MAXOFFSET ]); $self->{ignore} = 1; return; } # pass header $self->run_callback([ IMP_PASS,1,$self->offset(1) ]); } sub response_body { my ($self,$data) = @_; $self->{ignore} and return; my $off = $self->offset(1); if ( $data ne '' ) { $self->{image} .= $data; # append to image # replace with '' in caller to save memory there # at the end we will replace eof with the flipped image $self->run_callback([ IMP_REPLACE,1,$off,'' ]); # with chunked encoding we don't get a length up front, so check now if ( length($self->{image}) > MAX_SIZE ) { debug("image too big"); $self->run_callback( [ IMP_REPLACE,1,$off,$self->{image} ], # unchanged image [ IMP_PASS,1,IMP_MAXOFFSET ] ); $self->{ignore} = 1; } return; } # end of image reached, flip with Image::Magick debug("flip image size=%d",length($self->{image})); my $img = Image::Magick->new; debug("failed to flip img: $@") if ! eval { $img->BlobToImage($self->{image}); $img->Flip; ($self->{image}) = $img->ImageToBlob; debug("replace with ".length($self->{image})." bytes"); 1; }; $self->run_callback( [ IMP_REPLACE,1,$self->offset(1),$self->{image} ], [ IMP_PASS,1,IMP_MAXOFFSET ], ); } 1; __END__ =head1 NAME Net::IMP::HTTP::Example::FlipImg - sample IMP plugin to flip images =head1 SYNOPSIS # use proxy from App::HTTP_Proxy_IMP to flip images http_proxy_imp --filter Example::FlipImg listen_ip:port =head1 DESCRIPTION This is a sample plugin to flip PNG, GIF and JPEG with a size less than 32k.