Net-Server
view release on metacpan or search on metacpan
lib/Net/Server/HTTP.pm view on Meta::CPAN
sub initialize_logging {
my $self = shift;
$self->SUPER::initialize_logging(@_);
my $prop = $self->{'server'};
my $d = {
access_log_format => '%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"',
};
$prop->{$_} = $d->{$_} foreach grep {!defined($prop->{$_})} keys %$d;
$self->_init_access_log;
}
sub post_configure {
my $self = shift;
$self->SUPER::post_configure(@_);
my $prop = $self->{'server'};
# set other defaults
my $d = {
timeout_header => 15,
timeout_idle => 60,
server_revision => __PACKAGE__."/$Net::Server::VERSION",
max_header_size => 100_000,
};
$prop->{$_} = $d->{$_} foreach grep {!defined($prop->{$_})} keys %$d;
$self->_tie_client_stdout;
}
sub post_bind {
my $self = shift;
$self->SUPER::post_bind(@_);
$self->_check_dispatch;
}
sub _init_access_log {
my $self = shift;
my $prop = $self->{'server'};
my $log = $prop->{'access_log_file'};
return if (! $log || $log eq '/dev/null') && ! $prop->{'access_log_function'};
return if ! $prop->{'access_log_format'};
$prop->{'access_log_format'} =~ s/\\([\\\"nt])/$1 eq 'n' ? "\n" : $1 eq 't' ? "\t" : $1/eg;
if (my $code = $prop->{'access_log_function'}) {
if (ref $code ne 'CODE') {
die "Passed access_log_function $code was not a valid method of server, or was not a code object\n" if ! $self->can($code);
my $copy = $self;
$prop->{'access_log_function'} = sub { $copy->$code(@_) };
weaken $copy;
}
} elsif ($log eq 'STDOUT' || $log eq '/dev/stdout') {
open my $fh, '>&', \*STDOUT or die "Could not dup STDOUT: $!";
$fh->autoflush(1);
$prop->{'access_log_function'} = sub { print $fh @_,"\n" };
} elsif ($log eq 'STDERR' || $log eq '/dev/stderr') {
$prop->{'access_log_function'} = sub { print STDERR @_,"\n" };
} else {
open my $fh, '>>', $log or die "Could not open access_log_file \"$log\": $!";
$fh->autoflush(1);
push @{ $prop->{'chown_files'} }, $log;
$prop->{'access_log_function'} = sub { print $fh @_,"\n" };
}
}
sub _tie_client_stdout {
my $self = shift;
my $prop = $self->{'server'};
# install a callback that will handle our outbound header negotiation for the clients similar to what apache does for us
my $copy = $self;
$prop->{'tie_client_stdout'} = 1;
$prop->{'tied_stdout_callback'} = sub {
my $client = shift;
my $method = shift;
alarm($copy->timeout_idle); # reset timeout
my $request_info = $copy->{'request_info'};
if ($request_info->{'headers_sent'}) { # keep track of how much has been printed
my ($resp, $len);
if ($method eq 'print') {
$resp = $client->print(my $str = join '', @_);
$len = length $str;
} elsif ($method eq 'printf') {
$resp = $client->print(my $str = sprintf(shift, @_));
$len = length $str;
} elsif ($method eq 'say') {
$resp = $client->print(my $str = join '', @_, "\n");
$len = length $str;
} elsif ($method eq 'write') {
my $buf = shift;
$buf = substr($buf, $_[1] || 0, $_[0]) if @_;
$resp = $client->print($buf);
$len = length $buf;
} elsif ($method eq 'syswrite') {
$len = $resp = $client->syswrite(@_);
} else {
return $client->$method(@_);
}
$request_info->{'response_size'} = ($request_info->{'response_size'} || 0) + $len if defined $len;
return $resp;
}
die "All headers must only be sent via print ($method)\n" if $method ne 'print';
my $headers = ${*$client}{'headers'} ||= {buffer => '', status => undef, msg => undef, headers => []};
$headers->{'buffer'} .= join('', @_);
while ($headers->{'buffer'} =~ s/^(.*?)\015?\012//) {
my $line = $1;
if ($line =~ m{^HTTP/(1.[01]) \s+ (\d+) (?: | \s+ (.+?)) \s* $ }x) {
die "Found HTTP/ line after other headers were sent\n" if @{ $headers->{'headers'} };
@$headers{qw(version status msg)} = ($1, $2, $3);
}
elsif (! length $line) {
if (! $headers->{'status'} && ! @{ $headers->{'headers'} }) {
die "Premature end of script headers\n";
}
delete ${*$client}{'headers'};
$copy->send_status($headers);
if (my $n = length $headers->{'buffer'}) {
( run in 1.107 second using v1.01-cache-2.11-cpan-92ad3014f07 )