App-FonBot-Daemon
view release on metacpan or search on metacpan
lib/App/FonBot/Plugin/HTTPD.pm view on Meta::CPAN
use warnings;
use Apache2::Authen::Passphrase qw/pwcheck/;
use HTTP::Status qw/HTTP_BAD_REQUEST HTTP_OK HTTP_NO_CONTENT HTTP_FORBIDDEN HTTP_UNAUTHORIZED/;
use JSON qw/encode_json/;
use Log::Log4perl;
use POE::Component::Server::HTTP qw/RC_OK RC_DENY RC_WAIT/;
use DB_File;
use MIME::Base64 qw/decode_base64/;
use Storable qw/freeze thaw/;
use Text::ParseWords qw/shellwords/;
use App::FonBot::Plugin::Config qw/$httpd_port/;
use App::FonBot::Plugin::Common;
##################################################
my $log=Log::Log4perl->get_logger(__PACKAGE__);
my $httpd;
my %waiting_userrequests;
my %responses;
sub init{
$log->info('initializing '.__PACKAGE__);
%waiting_requests = ();
%waiting_userrequests = ();
$httpd = POE::Component::Server::HTTP->new(
Port => $httpd_port,
PreHandler => { '/' => [\&pre_auth, \&pre_get, \&pre_userget], },
ContentHandler =>{ '/send' => \&on_send, '/get' => \&on_get, '/ok' => \&on_ok, '/userget' => \&on_userget, '/usersend' => \&on_usersend },
ErrorHandler => { '/' => sub { RC_OK }},
Headers => { 'Cache-Control' => 'no-cache' },
);
}
sub fini{
$log->info('finishing '.__PACKAGE__);
POE::Kernel->call($httpd, 'shutdown');
}
##################################################
sub httpdie (\$$;$){
my ($response,$errstr,$errcode)=@_;
$$response->code($errcode // HTTP_BAD_REQUEST);
$$response->header(Content_Type => 'text/plain');
$$response->message($errstr);
die 'Bad Request';
}
sub pre_auth{
my ($request, $response)=@_;
eval {
my $authorization=$request->header('Authorization') // die 'No Authorization header';
$authorization =~ /^Basic (.+)$/ or die 'Invalid Authorization header';
my ($user, $password) = decode_base64($1) =~ /^(.+):(.*)$/ or die 'Invalid Authorization header';
eval { pwcheck $user, $password; 1 } or die 'Invalid user/password combination';
$request->header(Username => $user);
$log->debug("HTTP request from $user to url ".$request->url);
};
if (my $error = $@) {
$response->code(HTTP_UNAUTHORIZED);
$response->message('Bad username or password');
$response->header(Content_Type => 'text/plain');
$response->header(WWW_Authenticate => 'Basic realm="fonbotd"');
$response->content('Unauthorized');
$log->debug("Request denied: $error");
return RC_DENY
}
$response->content('');
RC_OK
}
sub pre_get{
my ($request, $response)=@_;
my $user=$request->header('Username');
return RC_OK if $response->code;
return RC_OK unless $user;
return RC_OK unless $request->uri =~ m,/get,;
unless (exists $commands{$user}) {
$log->debug("No pending commands for $user, entering RC_WAIT");
$waiting_requests{$user}->continue if exists $waiting_requests{$user};
$waiting_requests{$user}=$response;
return RC_WAIT
}
RC_OK
}
sub pre_userget{
my ($request, $response)=@_;
my $user=$request->header('Username');
return RC_OK if $response->code;
return RC_OK unless $user;
return RC_OK unless $request->uri =~ m,/userget,;
unless (exists $responses{$user}) {
$log->debug("No pending responses for $user, entering RC_WAIT");
$waiting_userrequests{$user}->continue if exists $waiting_userrequests{$user};
$waiting_userrequests{$user}=$response;
return RC_WAIT
}
RC_OK
}
sub on_ok{
my ($request, $response)=@_;
return RC_OK if $response->code;
$response->code(HTTP_OK);
RC_OK
}
sub on_get{
my ($request, $response)=@_;
return RC_OK if $response->code;
eval {
my $user=$request->header('Username');
$log->debug("on_get from user $user");
( run in 0.731 second using v1.01-cache-2.11-cpan-39bf76dae61 )