view Lib/IMPL/Web/Handler/RestController.pm @ 357:ec58c47edb52

web security: code cleanup, refactoring
author cin
date Fri, 18 Oct 2013 15:10:10 +0400
parents 71221d79e6b4
children 16ff604298c7
line wrap: on
line source

package IMPL::Web::Handler::RestController;
use strict;

use IMPL::Const qw(:prop);
use IMPL::declare {
	require => {
	    Locator => 'IMPL::Web::AutoLocator',
	    ResourceInterface => 'IMPL::Web::Application::ResourceInterface', 
		Exception => 'IMPL::Exception',
		ArgumentExecption => '-IMPL::InvalidArgumentException',
		NotFoundException => 'IMPL::Web::NotFoundException'
	},
	base => {
		'IMPL::Object' => undef,
		'IMPL::Object::Autofill' => '@_',
		'IMPL::Object::Serializable' => undef
	},
	props => [
	   resourceFactory => PROP_RO,
	   trailingSlash => PROP_RO
	]	
};

sub CTOR {
	my ($this) = @_;
	
	die ArgumentException->new(resourceFactory => "A web-resource is required")
	   unless $this->resourceFactory;
	   #unless eval { $this->resourceFacotry->isa(ResourceInterface) };
	 
}

sub GetResourcePath {
    my ($this,$action) = @_;
    
    my $pathInfo = $action->pathInfo;
    my @segments;
    
    if (length $pathInfo) {
    
        @segments = split(/\//, $pathInfo, $this->trailingSlash ? -1 : 0);
        
        # remove first segment if it is empty
        shift @segments if @segments && length($segments[0]) == 0;
    }
    
    return @segments;    
}


sub Invoke {
	my ($this,$request) = @_;
	
	my $method = $request->requestMethod;
	
	my @segments = $this->GetResourcePath($request);
	
	my $res = $this->resourceFactory->new(
	   id => 'root',
	   request => $request,
	   location => Locator->new(base => $request->application->baseUrl),
	);
	
	while(@segments) {
		my $id = shift @segments;
		$res = $res->FetchChildResource($id);
	}
	
	$res = $res->InvokeHttpVerb($method);
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Web::Handler::RestController> - Обрабатывает C<HTTP> запрос передавая
его соответствующему ресурсу.

=head1 SYNOPSIS

Используется в конфигурации приложения как элемент цепочки обработчиков.
Как правило располагается на самом верхнем уровне.

=begin code xml

    <handlers type="ARRAY">
        <item type="IMPL::Web::Handler::RestController">
            <resourceFactory>My::App::Web::RootResource</resourceFactory>
        </item>
        <item type="IMPL::Web::Handler::JSONView" />
        <item type="IMPL::Web::Handler::SecureCookie" />
        <item type="IMPL::Web::Handler::ErrorHandler" />
    </handlers>

=end code xml


=head1 DESCRIPTION

Использует C<PATH_INFO> для определения нужного ресурса, затем предает
найденному ресурсу управление для обработки запроса.

Если ресурс не найден, то возникает исключение C<IMPL::Web::NotFoundException>.

Для определения нужного ресурса контроллер разбивает C<PATH_INFO> на фрагменты
и использует каждый фрагмент для получения дочернего ресурса начиная с корневого.
Для чего используется метод
C<< IMPL::Web::Application::ResourceInterface->FetchChildResource($childId) >>.

Дерево ресурсов сущестувет независимо от обрабатываемого запроса, однако оно
может полностью или частично загружаться в начале обработки запроса и
освобождаться по окончании обработки запроса. Поэтому при получении дочерних
ресурсов не участвует C<HTTP> запрос, он адресуется только последнему ресурсу.

=begin text

/music/audio.mp3 -> ['music','audio.mp3']

=end text

=head1 MEMEBERS

=head2 C<[get]resourceFactory>

Фабрика для создания корневого ресурса приложения, полученный ресурс должен
реализовывать интерфейс C<IMPL::Web::Application::ResourceInterface>.

Фабрика может сохранять ссылку на корневой ресурс и каждый раз не создавать
его, а возвращать уже существующий. Это вполне оправдано, если хранение
дерева ресурсов требует меньше ресурсов, чем его создание и при этом приложение
остается в памяти между C<HTTP> запросами.

=head2 C<[get]trailingSlash>

Если данная переменная имеет значение C<true>, то слеш в конце пути к ресурсу
будет интерпретироваться, как дочерний ресурс с пустым идентификатором.

=cut