package Continuity::RequestHolder;
use strict;
use vars qw( $AUTOLOAD );
=for comment
We've got three layers of abstraction here. Looking at things from the
perspective of the native Web serving platform and moving towards
Continuity's guts, we have:
* Either HTTP::Request or else the FastCGI equiv.
* Continuity::Adapter::HttpServer::Request and
Continuity::Adapter::FCGI::Request both present a uniform interface
to the first type of object, and do HTTP protocol stuff not implemented
by them, such as parsing GET parameters.
This of this as the "Continuity::Request" object, except
* Continuity::RequestHolder (this object) is a simple fixed object for
the Continuity code hold to hold onto, that knows how to read
the second sort of object (eg, C::A::H::Request) from a queue and
delegates calls most tasks to that object.
We should move as much into here as possible, since it is used by all the
different Adaptors.
=cut
# Accessors
# This holds our current request
sub request { exists $_[1] ? $_[0]->{request} = $_[1] : $_[0]->{request} }
# Our queue of incoming requests
sub request_queue { exists $_[1] ? $_[0]->{request_queue} = $_[1] : $_[0]->{request_queue} }
# Used by the mapper to identify the whole queue
sub session_id { exists $_[1] ? $_[0]->{session_id} = $_[1] : $_[0]->{session_id} }
sub debug_level { exists $_[1] ? $_[0]->{debug_level} = $_[1] : $_[0]->{debug_level} } # Debug level (integer)
sub debug_callback { exists $_[1] ? $_[0]->{debug_callback} = $_[1] : $_[0]->{debug_callback} } # Debug callback
sub new {
my $class = shift;
my %args = @_;
exists $args{$_} or warn "new_requestHolder wants $_ as a parameter"
for qw/request_queue session_id/;
$args{request} = undef;
my $self = { %args };
bless $self, $class;
$self->Continuity::debug(2," ReqHolder: created, session_id: $args{session_id}");
bless $self;
}
sub next {
# called by the user's program from the context of their coroutine
my $self = shift;
go_again:
# If we still have an open request, close it
if($self->request) {
$self->Continuity::debug(2,"Closing old req: " . $self->request);
$self->request->end_request;
}
$self->{headers_sent} = 0;
# Here is where we actually wait for the next request
$self->request($self->request_queue->get);
if($self->request->immediate) {
goto go_again;
}
$self->Continuity::debug(2,"-----------------------------");
return $self;
}
sub print {
my $self = shift;
if(!$self->{headers_sent}) {
$self->request->send_basic_header();
$self->{headers_sent} = 1;
}
$self->request->print(@_);
return $self;
}
sub send_headers {
my $self = shift;
$self->{headers_sent} = 1;
$self->request->print(@_);
return $self;
}
# If we don't know how to do something, pass it on to the current continuity_request
sub AUTOLOAD {
# XXX always does scalar context... should do list/sclar as appropriate
my $method = $AUTOLOAD; $method =~ s/.*:://;
return if $method eq 'DESTROY';
my $self = shift;
my (@retval) = eval {
$self->request->can($method)
or die "request object doesn't implemented requested method\n";
$self->request->can($method)->($self->request, @_);
};
if($@) {
$self->Continuity::debug(1, "Continuity::RequestHolder::AUTOLOAD: Error delegating method ``$method'': $@");
}
return wantarray ? @retval : $retval[0];
}
1;