Web-MREST

 view release on metacpan or  search on metacpan

lib/Web/MREST.pm  view on Meta::CPAN


=head3 C<known_methods> (B12)

Returns the list of supported ("known") methods in 
C<< $site->MREST_SUPPORTED_HTTP_METHODS >>. If the request method is not
in that list, a C<501 Not Implemented> response is returned along with
an explanation that the method requested is not supported.

If this behavior is not appropriate, the method can be implemented by the
application.


=head3 C<uri_too_long> (B11)

If the request URI is longer than the value set in the C<MREST_MAX_LENGTH_URI> site parameter,
the client will receive a C<414 Request URI Too Long> response.

To override this behavior, provide your own C<uri_too_long> routine in your
resource module.

This functionality is demonstrated by the C<t/414-Request-URI-Too-Long.t> unit.


=head3 C<allowed_methods> (B10)

"Is the method allowed on this resource?"

This next routine is where things start to get complicated. According to the
L<Web::Machine::Resource
documentation|https://metacpan.org/pod/Web::Machine::Resource#allowed_methods>,
we are expected to respond with a list of methods allowed on the resource. To
assemble such a list, we must first answer two questions: 

=over

=item 1. Have the resource definitions been loaded?

=item 2. Does the URI match a known resource?

=back

After the server starts, the first time this method is called triggers a 
call to the C<init_router> method, which populates the C<$resources> package
variable in C<Web::MREST::InitRouter> with all the resource definitions.
This is explained in detail in L<"Resource definitions">. This takes care of
the first question.

The second question is answered by C<Path::Router>. Once the request has
been associated with a known resource, completing our task becomes a matter of
getting and returning the set of methods for which the resource is defined.


=head3 C<malformed_request> (B9)

A true return value from this method triggers a "400 Bad Request" response
status. RFC2616 does not stipulate exactly what constitutes a bad request.
We already (in allowed_methods) took care of the case when the URI 
fails to match a known resource, and that includes applying any C<validations> 
properties from the resource definition. 

So, in this method (or your overlay) we take the "next step" (whatever that is)
in vetting the request. Keep in mind that this method is called before 
the resource handler. If you have any sanity checks you wish to apply _after_
the URI is matched to a resource but _before_ the resource handler fires, this
is the place to put them.

If you would like to keep L<Web::MREST>'s implementation of this method
(which, for example, pushes the Content-Length and Content-Type information
onto the context) and add your own logic, you can put it in
C<mrest_malformed_request> instead of overriding C<malformed_request> itself.

If you intend to return false from this method you should first do this:

    $self->mrest_declare_status( explanation => '...' );

to ensure that an explanation is included with the 400 response.


=head3 C<is_authorized> (B8)

In my mind, "authentication" is the process of determining who the user 
is, and "authorization" determines if the user is allowed to do what she
is asking to do. However, RFC2616 does not make such a clear distinction.

For that reason, it is left to the application to implement this method
if needed.


=head3 C<forbidden> (B7)

The same thoughts as expressed under C<is_authorized>, above, apply to 
this method as well.


=head3 C<valid_content_headers> (B6)

This is where you vet the C<Content-*> headers in the request. If the 
request contains any invalid C<Content-*> headers (i.e., if the '*' part
does not appear in << $site->MREST_VALID_CONTENT_HEADERS >>), 
a 501 will be generated.

The content headers are passed to the method in a L<Hash::MultiValue>
object.


=head3 C<known_content_type> (B5)

If the C<Content-Type> header is relevant - i.e., if this is a PUT or
POST request and if there is a request entity - check it against 
<< $site->MREST_SUPPORTED_CONTENT_TYPES >>.


=head3 C<valid_entity_length> (B4)

A simple routine that compares the entity length (in bytes) with the 
maximum set in C<< $site->MREST_MAX_LENGTH_REQUEST_BODY >>.


=head3 C<options> (B3)

If your application needs to support the C<OPTIONS> method, you should 

lib/Web/MREST.pm  view on Meta::CPAN

    - 'documentation' is reserved for the self-documentation feature



=head3 C<Path::Router> object initialization

When the server starts, the C<MREST_RESOURCE_DEFINITIONS> and
C<MREST_ROOT_RESOURCE> meta parameters are initialized from the configuration
file C<config/dispatch_MetaConfig.pm> in the L<Web::MREST> distribution.

The application developer will of course want to define her own set of
resources. This should be done by manipulating the meta parameters
C<MREST_RESOURCE_DEFINITIONS> and C<MREST_ROOT_RESOURCE>. A good place
to do this is in the application's C<mrest_init_router> routine. 

Here are two approaches to defining the application's resources, depending on
whether the application wishes to retain the L<Web::MREST> resources.  

=over

=item 1. retain

    package MyApp::Resource;

    use Clone 'clone';
    use parent 'Web::MREST::Resource';

    # We assume that the application somehow loads its resource definitions
    # (including the root resource) into a package variable $r_defs -- for
    # example by hard-coding them like this
    my $r_defs = { ... };

    # ----------------------------------------
    # mrest_init_router - called by Web::MREST
    # ----------------------------------------
    sub mrest_init_router {
        my $self = shift;

        # set up the root resource
        $meta->set( 'MREST_ROOT_RESOURCE', $r_defs->{''} );
        delete $r_defs->{''};

        # set up the remaining resources, retaining (but possibly
        # overwriting) the Web::MREST default resources
        my $mrest_defs = clone( $meta->MREST_RESOURCE_DEFINITIONS );
        foreach my $r_name ( keys %$r_defs ) {
            $mrest_defs->{$r_name} = $r_defs->{$r_name};
        }
        $meta->set( 'MREST_RESOURCE_DEFINITIONS', $mrest_defs );
    }

=item 2. do not retain

This approach is more simple because no C<mrest_init_router> need be written.
The application should have its own distro sharedir C<config/> and therein a
file C<dispatch_MetaConfig.pm>.  Inside that file, the application puts its own
resource definitions in the C<MREST_RESOURCE_DEFINITIONS> and
C<MREST_ROOT_RESOURCE> parameters (refer to C<config/dispatch_MetaConfig.pm> in
the L<Web::MREST> distribution for syntax and semantics).

The application's definitions will overlay (i.e. replace) those of
L<Web::MREST>.  Even in this scenario, some or all of L<Web::MREST>'s resources
could be used in the application, but only by copy-pasting the definitions and
their respective handlers into the application's source code.

=back


=head3 Tree structure

L<Web::MFILE> allows resources to be defined in a tree structure.  It is
designed to allow a tree structure to be described in a flat configuration
file. The C<MREST_RESOURCE_DEFINITIONS> hash is keyed on the resource name.
Child resources are indicated by including a C<parent> property with the name
of the parent resource. Care should be exercised not to introduce any circular
references.

If a flat structure is desired, simply do not include any C<parent> properties
in your resource definitions.

The format of C<MREST_RESOURCE_DEFINITIONS> hash is documented in
C<config/dispatch_MetaConfig.pm>. 


=head3 C<< $Web::MREST::InitRouter::resources >> 

The resource definition hashrefs in the dispatch modules are designed to be
written and maintained by humans. When the C<init_router> method runs, it loops
over all the resource definitions and builds up a second hash,
C<< $Web::MREST::InitRouter::resources >>, which contains the same information
in a format that is more convenient for automated processing.

Since the resource definitions are a potential source of typographical and
semantic errors, you should dump this package variable to the log and examine
it to make sure your resource definitions are being processed correctly.


=head2 Errors

As we move through the state machine (i.e. the chain of method calls driven
by L<Web::Machine>), we build up a "context" from which we generate the HTTP
response. Stated very simply, the response code can either be 'OK' (200) or
"something else" - i.e., an error of some kind.

And, indeed, checking for errors accounts for a large portion of what our
resource modules do. As RFC2616 explains, errors can be divided into two
brought classes: client errors and server errors.

=over

=item Client errors (4xx)

Client errors have status codes that start with 4 (e.g. 400, 401, 404).

RFC2616 has this to say about them:

    The 4xx class of status code is intended for cases in which the client
    seems to have erred. Except when responding to a HEAD request, the server
    SHOULD include an entity containing an explanation of the error situation, and
    whether it is a temporary or permanent condition. These status codes are
    applicable to any request method. User agents SHOULD display any included

lib/Web/MREST.pm  view on Meta::CPAN

prone to abuse by individuals who are willing to lie about their identity.

Humans are good at distinguishing one human from another, provided they can
apply all their senses to the task. Computers lack proper senses and are
downright awful at this task. Computerized authentication schemes typically
operate by presenting the user with one or more hoops to jump through. Whoever
succeeds at this task is deemed to be the user. What could go wrong?

Passwords (or passphrases) are the "hoop" most frequently used to authenticate
users and keep would-be intruders out. Therefore, a system's security is often
gauged by how well it protects user credentials from disclosure. Since
usernames are public, the only thing keeping a determined intruder at bay are
the passwords, and various measures are taken to protect them. 

From the perspective of L<Web::Machine>, authentication is a matter of 
calling the L<is_authorized> method. If the return value is false, the response
will be C<401 Unauthorized>. If it is true, request processing continues.
Whatever authentication measures the application developer decides to implement
should be triggered by this method call.

For more about L<is_authorized>, see the L<Web::Machine::Resource documentation|https://metacpan.org/pod/Web::Machine::Resource#is_authorized-authorization_header>



=head2 Authorization

Once authentication has determined the user's identity, a related task,
authorization, begins. As the name would imply (and the RFC's vague
use of the term "authorization" notwithstanding), authorization answers
the question:

    Is this specific user authorized to make this request?

Compare this with authentication, which answers a different question:

    Is this user really who they are purporting to be?

Or, even more pithily:

    Who is this user?

Authorization implies a boolean "function" (in both the mathematical and
computer science sense) that takes three arguments: the username, the HTTP
method, and the resource. Implementation of this function is left to the
application developer.

It is worth noting here that L<Web::Machine> provides a C<forbidden> method.
Since C<is_authorized> is already taken for authentication, we can use
C<forbidden> for authorization. Just be sure to understand thoroughly that
a true return value from C<forbidden> means "not authorized".


=head2 Customized URI parsing

While L<Web::MREST> provides for URI parsing using L<Path::Router>, if this is
not desired the application developer can parse URIs herself by simply
substituting her own C<init_router> and C<match> methods for the ones provided
by L<Path::Router> and L<Path::Router::Route::Match>, respectively.

When request processing enters C<resource_exists>, 
Alternatively, the application developer can overlay the C<init_router> routine
with one that returns an arbitrary object (stored in C<$router>) that has a
C<match> method. After that, L<Web::MREST> does

    my $match = $router->match( $path );

where C<$path> is the relative portion of the URI (i.e. everything left after
the C<http://myapp.example.com/> part is cut off).

The C<$match> object should provide a C<route> method, which should return the
definition of the matched resource. See L<"RESOURCE DEFINITIONS">.


=head1 FUNCTIONS IN THIS MODULE

=head2 init

Do initialization-like things, such as loading configuration parameters.
Takes a PARAMHASH which can contain one of the following:

=over

=item C<distro>

The name of the application distribution from which the distro sharedir will be
loaded.

=item C<path>

The name (full path) of a directory containing the application's configuration
files.

=item C<hashref>

A reference to a hash containing meta parameters to be loaded.

=back

=cut 

sub init {
    my %ARGS = validate( @_, {
        distro => { type => SCALAR, optional => 1 },
        sitedir => { type => SCALAR, optional => 1 },
        hashref => { type => HASHREF, optional => 1 },
        early_debug => { type => SCALAR, optional => 1 },
    } );
    
    my $tf = $ARGS{'early_debug'};
    if ( $tf ) {
        _touch $tf;
        if ( -r $tf and -w $tf ) {
            unlink $tf;
            Log::Any::Adapter->set( 'File', $tf );
            $log->debug( __PACKAGE__ . "::init activating early debug logging to $tf" );
        } else {
            print "Given unreadable/unwritable early debugging filespec $tf\n";
        }
    }

    # always load Web::MREST's configuration parameters



( run in 0.581 second using v1.01-cache-2.11-cpan-39bf76dae61 )