Agent-TCLI-Package-Net
view release on metacpan or search on metacpan
lib/Agent/TCLI/Package/Net/HTTPD.pm view on Meta::CPAN
usage: httpd set hostname=example.com
---
Agent::TCLI::Command:
name: show
call_style: session
command: tcli_httpd
contexts:
httpd: show
handler: show
help: show tail default settings and state
parameters:
logging:
address:
port:
hostname:
regex:
response:
handlers:
ports:
topic: testing
usage: httpd show settings
...
}
sub _start {
my ($kernel, $self, $session) =
@_[KERNEL, OBJECT, SESSION];
$self->Verbose("_start: tcli httpd starting");
# are we up before OIO has finished initializing object?
if (!defined( $self->name ))
{
$kernel->yield('_start');
return;
}
# There is only one command object per TCLI
$kernel->alias_set($self->name);
$self->handlers( [
{
'DIR' => '.*',
'SESSION' => $self->name,
'EVENT' => 'NA404',
},
] ) unless defined($self->handlers);
$self->Verbose("_start Dump ".$self->dump(1),3);
}
sub _shutdown :Cumulative {
my ($kernel, $self, $session) =
@_[KERNEL, OBJECT, SESSION];
$self->Verbose($self->name.':_shutdown:');
foreach my $port ( keys %{ $self->ports } )
{
$self->Verbose("_shutdown: $port");
$kernel->post( 'HTTPD'.$port , 'SHUTDOWN' );
}
return ('_shutdown '.$self->name )
}
sub _stop {
my ($kernel, $self,) =
@_[KERNEL, OBJECT,];
$self->Verbose("_stop: ".$self->name." stopping",2);
}
=item spawn
This POE event handler executes the spawn command to start a new HTTPD listener.
=cut
sub spawn {
my ($kernel, $self, $sender, $request, ) =
@_[KERNEL, OBJECT, SENDER, ARG0, ];
my $txt = '';
my $param;
my $command = $request->command->[0];
my $cmd = $self->commands->{$command};
return unless ( $param = $cmd->Validate($kernel, $request, $self) );
$self->Verbose("spawn: param dump",4,$param);
# is one running already?
if (exists( $self->ports->{ $param->{'port'} } ))
{
$self->Verbose("spawn: ".$param->{'port'}." already running");
$request->Respond($kernel,"HTTPD server on port ".
$param->{'port'}." already running",400);
return;
}
# Start the server!
$self->ports->{ $param->{'port'} } =
POE::Component::Server::SimpleHTTP->new(
'ALIAS' => 'HTTPD'.$param->{'port'},
'ADDRESS' => defined($param->{'address'})
? $param->{'address'}
: $sender->get_heap->local_address,
'PORT' => $param->{'port'},
'HOSTNAME' => defined($param->{'hostname'})
? $param->{'hostname'}
: '',
'HANDLERS' => $self->handlers,
# 'LOGHANDLER' => {
# 'SESSION' => $self->name,
# 'EVENT' => 'Log',
# },
# In the testing phase...
# 'SSLKEYCERT' => [ 'public-key.pem', 'public-cert.pem' ],
);
unless (defined( $self->ports->{ $param->{'port'} } ) )
{
$request->Respond($kernel,'Unable to create the HTTPD Server',400);
return;
}
# store the $sender for later use.
$self->SetWheelKey($param->{'port'}, 'control' => $sender );
$request->Respond($kernel,'HTTPD Started on port '.$param->{'port'},200);
}
=item stop
This POE Event handler executes the stop command to shutdown a HTTPD listener.
=cut
sub stop {
my ($kernel, $self, $sender, $request, ) =
@_[KERNEL, OBJECT, SENDER, ARG0, ];
my $txt = '';
my $param;
my $command = $request->command->[0];
my $cmd = $self->commands->{$command};
return unless ( $param = $cmd->Validate($kernel, $request, $self) );
$self->Verbose("spawn: param dump",4,$param);
unless (defined( $self->ports->{ $param->{'port'} } ) )
{
$request->Respond($kernel,'Unable to locate the HTTPD Server',404);
return;
}
$kernel->post( 'HTTPD'.$param->{'port'} , 'SHUTDOWN' );
# remove the stored control for this server
$self->SetWheelKey( $param->{'port'} , 'control' );
delete( $self->ports->{ $param->{'port'} } );
$request->Respond($kernel,'HTTPD Stopped on port '.$param->{'port'},200);
}
=item uri
This POE Event handler excecutes the uri add and uri delete commands.
=cut
sub uri {
my ($kernel, $self, $sender, $request, ) =
@_[KERNEL, OBJECT, SENDER, ARG0, ];
my $txt = '';
my $code;
my $param;
my $command = $request->command->[0];
my $cmd = $self->commands->{'uri_'.$command};
return unless ( $param = $cmd->Validate($kernel, $request, $self) );
if ( $command eq 'add' )
{
my $last = $self->pop_handlers;
$self->push_handlers(
{
'DIR' => $param->{'regex'},
'SESSION' => $self->name,
'EVENT' => $param->{'response'},
},
$last
);
$txt = 'uri added';
$code = 200;
}
elsif ( $command eq 'delete' )
{
my $i = 0;
$txt = "regex not found, delete failed";
$code = 404;
# This will loop over the handlers and removel ALL matches.
foreach my $handler ( @{$self->handlers} )
{
if ( $param->{'regex'} eq $handler->{'DIR'} &&
$i != $self->depth_handlers ) # Don't remove last one, ever.
{
my $goner = splice( @{$self->handlers},$i,1 );
$txt .= "regex ".$goner->{'DIR'}." with response ".
$goner->{'EVENT'}." deleted \n";
$code = 200;
}
$i++;
}
}
$request->Respond($kernel,$txt,$code);
}
=item BeGone
This POE Event handler is used as a target event for URIs. It simply drops the
connection. It will log the conenction if logging is turned on.
=cut
sub BeGone {
# ARG0 = HTTP::Request object, ARG1 = HTTP::Response object,
# ARG2 = the DIR that matched
my ($kernel, $self, $request, $response, $dirmatch ) =
@_[KERNEL, OBJECT, ARG0 .. ARG2 ];
my $port = $response->connection->local_port;
# Do our stuff to HTTP::Response
$response->code( 0 );
$kernel->call($self->name => 'Log' => $request, $response ) if $self->logging;
$kernel->post( 'HTTPD'.$port , 'CLOSE', $response );
}
=item OK200
This POE Event handler is used as a target event for URIs. It will
send an HTTP response code of 200 with the content 'OK'.
It will log the conenction if logging is turned on.
=cut
sub OK200 {
# ARG0 = HTTP::Request object, ARG1 = HTTP::Response object,
# ARG2 = the DIR that matched
my ($kernel, $self, $request, $response, $dirmatch ) =
@_[KERNEL, OBJECT, ARG0, ARG1, ARG2 ];
my $port = $response->connection->local_port;
# Do our stuff to HTTP::Response
$response->code( 200 );
$response->content( 'OK' );
$kernel->call( $self->name => 'Log' => $request, $response ) if $self->logging;
$kernel->post('HTTPD'.$port, 'DONE', $response );
}
=item NA404
This POE Event handler is used as a target event for URIs. It will
send an HTTP response code of 404 with an error message.
It will log the conenction if logging is turned on.
=cut
sub NA404 {
# ARG0 = HTTP::Request object, ARG1 = HTTP::Response object,
# ARG2 = the DIR that matched
my ($kernel, $self, $request, $response, $dirmatch ) =
@_[KERNEL, OBJECT, ARG0 .. ARG2 ];
my $port = $response->connection->local_port;
# Check for errors
if ( ! defined $request ) {
$_[KERNEL]->post( 'HTTPD'.$port, 'DONE', $response );
return;
}
# Do our stuff to HTTP::Response
$response->code( 404 );
$response->content( "Hi visitor from " . $response->connection->remote_ip.
", Page not found -> '" . $request->uri->path . "'" );
$kernel->call($self->name => 'Log' => $request, $response ) if $self->logging;
$kernel->post('HTTPD'.$port, 'DONE', $response );
}
=item Log
This POE Event handler is used internally to provide the logging. It sends
the time, remote ip:port, local ip:port, uri and optionally the SSL cipher
to the Tail session.
=back
=cut
sub Log {
my ($kernel, $self, $request, $response) =
@_[KERNEL, OBJECT, ARG0 , ARG1];
$self->Verbose("Log: request(".$request->uri);
my $port = $response->connection->local_port;
my $log;
# If the request was malformed, $request = undef
if ( $request )
{
$log = join (' ',
time(),
$response->connection->remote_ip.':'.$response->connection->remote_port,
$response->connection->local_ip.':'.$port,
$response->code,
$request->uri,
$response->connection->ssl ? $response->connection->sslcipher : '',
)."\n";
}
else
{
$log = join (' ',
time(),
$response->connection->remote_ip.':'.$response->connection->remote_port,
$response->connection->local_ip.':'.$port,
$response->code,
'Bad request',
$response->connection->ssl ? $response->connection->sslcipher : '',
)."\n";
}
# In the future we'll need to resolve port to control to send to correct tail
my $control = $self->GetWheelKey( $port, 'control');
$kernel->post('tcli_tail', 'Append', $log );
return;
}
1;
#__END__
=head3 INHERITED METHODS
This module is an Object::InsideOut object that inherits from Agent::TCLI::Package::Base. It
inherits methods from both. Please refer to their documentation for more
details.
=head1 AUTHOR
Eric Hacker E<lt>hacker at cpan.orgE<gt>
=head1 BUGS
One cannot add uri's while a HTTPD server is running.
SHOULDS and MUSTS are currently not enforced.
Test scripts not thorough enough.
Probably many others.
=head1 LICENSE
Copyright (c) 2007, Alcatel Lucent, All rights resevred.
This package is free software; you may redistribute it
and/or modify it under the same terms as Perl itself.
=cut
( run in 0.757 second using v1.01-cache-2.11-cpan-5735350b133 )