The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Dancer2::Plugin::HTTP::ConditionalRequest - RFC 7232 compliant

VERSION

Version 0.01

SYNOPSIS

Conditionally handling HTTP request based on eTag or Modification-Date, according to RFC 7232

HTTP Conditional Requests are used for telling servers that they only have to perform the method if the preconditions are met. Such requests are either used by caches to (re)validate the cached response with the origin server - or - to prevent lost-updates with unsafe-methods in a stateless api (like REST).

    any '/my_resource/:id' => sub {
        ...
        # check stuff
        # - compute eTag from MD5
        # - use an external table
        # - find a last modification date
        ...
        
        http_conditional {
            etag            => '2d5730a4c92b1061',
            last_modified   => "Tue, 15 Nov 1994 12:45:26 GMT", # HTTP Date
            required        => false,
        }
        
        # do the real stuff, like updating or serializing
        
    };

RFC_7232 HTTP: Conditional Requests... explained

As mentioned in the previous section, Conditional Requests are for two purposes mainly:

Caching

For GET and HEAD methods, the caching-server passes the validators to the origin server to see if it can still use the cached version or not - and if not, get a fresh version.

Keep in mind that the Dancer2 server is probably designed to be that originating server and should provide either the 304 (Not Modified) status or a fresh representation off the requested resource. At this stage (and in compliance with the RFC) there is nothing to deal with the caching of the responses at all.

This plugin does not do any caching, it's only purpose is to respond correctly to conditional requests. Neither does this plugin set any caching-directives that are part of RFC_7234 (Caching), and for which there is a seperate plugin.

Lost-Updates

For REST api's it is important to understand that it is a Stateless interface. This means that there is no such thing as record locking on the server. Would one desire to edit a resource, the only way to check that one is not accidently overwritin someone elses changes, is comparing it with weak or strong validators, like date/time of a last modification - or a unique version identifier, known as a eTag.

Strong and weak validators

ETags are stronger validators than the Date Last-Modified. In the above described example, it has two validators provided that can be used to check the conditional request. If the client did set an eTag conditional in 'If-Matched' or 'If-None-Matched', it will try to match that. If not, it will try to match against the Date Last-Modified with either the 'If-Modified-Since' or 'If-Unmodified-Since'.

Required or not

The optional 'required' turns the API into a strict mode. Running under 'strict' ensures that the client will provided either the eTag or Date-Modified validator for un-safe requests. If not provided when required, it will return a response with status 428 (Precondition Required) (RFC 6585).

When set to false, it allows a client to sent of a request without the headers for the conditional requests and as such have bypassed all the checks end up in the last validation step and continue with the requested operation.

Safe and unsafe methods

Sending these validators with a GET request is used for caching and respond with a status of 304 (Not Modified) when the client has a 'fresh' version. Remember though to send of current caching-information too (according to the RFC 7232).

When used with 'unsafe' methods that will cause updates, these validators can prevent 'lost updates' and will respond with 412 (Precondition Failed) when there might have happened an intermediate update.

Generating eTags and Dates Last-Modified

Unfortunately, for a any method one might have to retrieve and process the resource data before being capable of generating a eTag. Or one might have to go through a few pieces of underlying data structures to find that last-modification date.

For a GET method one can then skip the 'post-processing' like serialisation and one does no longer have to send the data but only the status message 304 (Not Modified).

More reading

There is a lot of additional information in RFC-7232 about generating and retrieving eTags or last-modification-dates. Please read-up in the RFC about those topics.

Dancer2 Keywords

http_conditional

This keyword used will check with the passed in parameters to do a conditional request. If these pre-conditions are not met execution will be halted with the relevant status code. If the preconditions apply, execution will continue on the following line.

A optional hashref takes the options

etag

a string that 'uniquely' identifies the current version of the resource.

last_modified

a HTTP Date compliant string of the date/time this resource was last updated.

or

a DateTime object.

A suitable string can be created from a UNIX timestamp using HTTP::Date::time2str, or from a DateTime object using format_datetime from DateTime::Format::HTTP.

required

if set to true, it enforces clients that request a unsafe method to provide one or both validators.

If used with either a GET or a HEAD method, the validators mentioned in the options are set and returned in the appropriate HTTP Header Fields.

AUTHOR

Theo van Hoesel, <Th.J.v.Hoesel at THEMA-MEDIA.nl>

BUGS

Please report any bugs or feature requests to bug-dancer2-plugin-http-conditionalrequest at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Dancer2-Plugin-HTTP-ConditionalRequest. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Dancer2::Plugin::HTTP::ConditionalRequest

You can also look for information at:

ACKNOWLEDGEMENTS

LICENSE AND COPYRIGHT

Copyright 2015-2016 Theo van Hoesel.

This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:

http://www.perlfoundation.org/artistic_license_2_0

Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.

If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.

This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.

This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.

Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.