Crop-Config
view release on metacpan or search on metacpan
lib/Crop/Server.pm view on Meta::CPAN
});
(end code)
=cut
use v5.14;
use warnings;
no warnings 'experimental';
use Encode qw/ decode /;
use XML::LibXSLT;
use XML::LibXML;
use XML::Simple;
use JSON;
use CGI::Cookie;
use FindBin qw/ $RealBin /;
use Crop::Debug;
use Crop::Error qw/ all_right warn /;
use Crop::Server::Constants;
use Crop::Server::Handler;
use Crop::HTTP::Session;
use Crop::DateTime;
use Crop::Client;
use Crop::Rights;
=begin nd
Constant: HOMEPAGE
Homepage of the web-site is always '/'
=cut
use constant {
HOMEPAGE => '/',
};
=begin nd
Variable: our @EXPORT
Export by default:
OK - handler return status
=cut
our @EXPORT = qw/ OK PAGELESS /;
=begin nd
Variable: our %Attributes
Attributes:
auth - if true an autentication is required; since true by default, you should redefine the <authenticate ( )> method
client - client ID
content - body of the response
cwd - current working directory
data - persistent data across all the handlers of an client request
json - JSON exemplar
handler - hash of registered handlers
headers - HTTP headers for response
iflow - Input flow of data (see <I ( )>)
oflow - Output flow of data (see <O ( )>)
special item named {ERROR} contains hashref of all the errors ocquired (see <Crop::Error>)
output_t - type of output ('XML', 'XSLT', 'JSON', and so on)
page - filename of output template in cwd
redirect - URL to redirect
request - client request object, <Crop::HTTP::Request> exemplar; will be Saved manually, so stable=>1
rights - rights granted to the client, exemplar of <Crop::Rights>
router - method establishes a chain of handlers calls; the reuslt of method is array of handler names
sendfile - exemplar of <Crop::File::Send> allowes to download file <Crop::File> from inner url (for Nginx)
session - exemplar of <Crop::HTTP::Session>
tik - start time of request as <Crop::DateTime> object; server sets a corresponding tok at done time
user - user object
workqueue - array of handlers names establishes executing order
xslt - hash of parsed XSLT templates
The 'stable' attribute means 'do not cleanup after request has done'.
=cut
our %Attributes = (
auth => {default => 1, stable => 1},
client => {mode => 'read'},
content => undef,
cwd => {stable => 1},
data => undef,
json => {stable => 1},
handler => {stable => 1},
headers => undef,
iflow => undef,
oflow => {mode => 'read'},
output_t => {default => 'XSLT', stable => 1},
page => undef,
redirect => undef,
request => {mode => 'read', stable => 1},
rights => {mode => 'read'},
router => {mode => 'write', stable => 1}, # the same all the time, altough result changes
sendfile => {mode => 'read/write'},
session => {mode => 'read', stable => 1}, # temporary hack!!! needed by $S->session->restore_param in a script
tik => {mode => 'read'},
user => undef,
workqueue => undef,
xslt => {stable => 1},
);
=begin nd
Variable: our $Server
Singlton.
<Crop> 'uses' this class, so Server object must be available from outer classes by accessing directly
without use of methods of this class.
Getter is <instance ( )>.
=cut
our $Server;
=begin nd
Variable: my $Interrupted
Signal to interrupt the Server has received.
Variable: my $AtWork
Server at work should not be killed.
=cut
my ($Interrupted, $AtWork);
# Try the Server to be terminated correctly as possible
$SIG{TERM} = $SIG{INT} = \&interrupt;
=begin nd
lib/Crop/Server.pm view on Meta::CPAN
$self->{session}->id_client($client->id);
}
$self->{request}->id_session($session->id);
$self->{request}->cookie_out($session->cookie);
# parse the input flow before the dispatcher starts their work since it operate on input parameters
$self->{iflow} = {};
$self->{oflow} = {};
# init data persistent across all the handlers in request
$self->{data} = {};
# parse input params
$self->_parse_input;
my $json;
if (defined $self->{request}->content_t and $self->{request}->content_t eq 'application/json') {
$json = $self->{iflow}{POSTDATA};
} elsif (exists $self->{iflow}{json} and keys %{$self->{iflow}} == 1) {
$json = $self->{iflow}{json};
}
$self->_parse_json($json) if $json;
# Authentication
if ($self->{auth}) {
$self->_authenticate or warn 'AUTH: Authentication failed';
}
# define handlers order
$self->{workqueue} = defined $self->{router} ? $self->{router}->($self) : ['DEFAULT'] or warn 'NOHANDLER|CRIT: No any handler match the request';
$self->{workqueue} = [$self->{workqueue}] unless ref $self->{workqueue}; # make arrayref, so router may return handler name as a plain string
# page could be redefined by handler
$self->{page} = DEFAULT_TPL;
}
=begin nd
Function: interrupt ($signal)
Handler of TERM or INT signals.
Interrupt Server gracefully.
The Apache web server sends TERM for '$ apachectl graceful' command.
This function uses global 'my' variables instead of server attributes for cut dependency of Server constructor.
Parameters:
$signal - signal
=cut
sub interrupt {
my $signal = shift;
warn "SERVER|NOTICE: The $signal signal received";
$AtWork ? $Interrupted = 1 : die 'SERVER|NOTICE: Server stoped';
};
=begin nd
Method: _init_httprequest ( )
Create <Crop::HTTP::Request> object from client data.
Pure virtual method.
=cut
sub _init_httprequest { warn 'Crop::Server::_init_httprequest() must be redefined by a subclass' }
=begin nd
Method: instance ( )
Get Singlton.
Returns:
$Server object as an singlton.
=cut
sub instance { $Server }
=begin nd
Method: _is_json_correct ($json)
Check incomming JSON for correctness.
Input should consists of hashref where items are scalar either hashref.
Tree traverse uses a loop+stack.
Returns:
1 - is correct
undef - otherwise
=cut
sub _is_json_correct {
my ($self, $json) = @_;
# 'left' contains a names of json objects of current node were not processed
# 'node' is the current item of parsing; if left=undef, node were not processed
my @stack = {left => undef, node => $json};
while (my $frame = pop @stack) {
my $node = $frame->{node};
next unless ref $node;
if (ref $node eq 'HASH') {
# remember keys of child nodes at the begining of parsing current node
$frame->{left} = [keys %$node] unless defined $frame->{left};
@{$frame->{left}} or next; # all childs is done
my $key = pop @{$frame->{left}};
# frame with remaining nodes goes back to the stack for a later parsing
push @stack, $frame;
# no info about this node, so 'left' is undef
push @stack, {left => undef, node => $node->{$key}};
} elsif (ref $node eq 'ARRAY') {
# debug 'ARRAY_AT_JSON';
} elsif (ref $node eq 'JSON::PP::Boolean') {
# $$node = 0 or 1; boolean type
} else {
return warn 'INPUT: JSON parsing error'; # json is incorrect
}
}
1;
}
( run in 0.748 second using v1.01-cache-2.11-cpan-39bf76dae61 )