HTTP-Promise

 view release on metacpan or  search on metacpan

lib/HTTP/Promise/Headers.pm  view on Meta::CPAN

    use IO::File;
    use Module::Generic::Global qw( :const );
    use Scalar::Util;
    use URI::Escape::XS ();
    use Wanted;
    if( exists( $ENV{MOD_PERL} )
        &&
        ( $MOD_PERL = $ENV{MOD_PERL} =~ /^mod_perl\/(\d+\.[\d\.]+)/ ) )
    {
        select( ( select( STDOUT ), $| = 1 )[ 0 ] );
        require Apache2::Log;
        # For _is_class_loaded method
        require Apache2::Module;
        require Apache2::ServerUtil;
        require Apache2::RequestUtil;
        require Apache2::ServerRec;
        require ModPerl::Util;
        require Apache2::Const;
        Apache2::Const->import( compile => qw( :log OK ) );
    }
    use constant CRLF => "\015\012";
    our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
    our $SUPPORTED = {};
    our $VERSION = 'v0.3.3';
};

use strict;
use warnings;

my $stderr = IO::File->new;
$stderr->fdopen( fileno( STDERR ), 'w' );
$stderr->binmode( ':utf8' );
$stderr->autoflush( 1 );
my $stderr_raw = IO::File->new;
$stderr_raw->fdopen( fileno( STDERR ), 'w' );
$stderr_raw->binmode( ':raw' );
$stderr_raw->autoflush( 1 );

our $MOD_PATH = Cwd::abs_path( $INC{ ( __PACKAGE__ =~ s{::}{/}gr ) . '.pm' } );

# for mod in `ls -1 ./lib/HTTP/Promise/Headers`; do printf "%-32s => 'HTTP::Promise::Headers::%s',\n" $(echo $(basename $mod ".pm")|tr "[:upper:]" "[:lower:]") $(basename $mod ".pm"); done
# or
# perl -MModule::Generic::File=file -lE 'my $d=file("./lib/HTTP/Promise/Headers"); my $files=$d->content; $files->for(sub{ my$f=file($_); printf("%-32s => ''HTTP::Promise::Headers::%s'',\n", $f->basename(".pm")->lc, $f->basename(".pm")) })'
our $SUPPORTED =
{
    accept                           => 'HTTP::Promise::Headers::Accept',
    acceptencoding                   => 'HTTP::Promise::Headers::AcceptEncoding',
    acceptlanguage                   => 'HTTP::Promise::Headers::AcceptLanguage',
    altsvc                           => 'HTTP::Promise::Headers::AltSvc',
    cachecontrol                     => 'HTTP::Promise::Headers::CacheControl',
    clearsitedata                    => 'HTTP::Promise::Headers::ClearSiteData',
    contentdisposition               => 'HTTP::Promise::Headers::ContentDisposition',
    contentrange                     => 'HTTP::Promise::Headers::ContentRange',
    contentsecuritypolicy            => 'HTTP::Promise::Headers::ContentSecurityPolicy',
    contentsecuritypolicyreportonly  => 'HTTP::Promise::Headers::ContentSecurityPolicyReportOnly',
    contenttype                      => 'HTTP::Promise::Headers::ContentType',
    cookie                           => 'HTTP::Promise::Headers::Cookie',
    expectct                         => 'HTTP::Promise::Headers::ExpectCT',
    forwarded                        => 'HTTP::Promise::Headers::Forwarded',
    generic                          => 'HTTP::Promise::Headers::Generic',
    keepalive                        => 'HTTP::Promise::Headers::KeepAlive',
    link                             => 'HTTP::Promise::Headers::Link',
    range                            => 'HTTP::Promise::Headers::Range',
    servertiming                     => 'HTTP::Promise::Headers::ServerTiming',
    stricttransportsecurity          => 'HTTP::Promise::Headers::StrictTransportSecurity',
    te                               => 'HTTP::Promise::Headers::TE',
    wantdigest                       => 'HTTP::Promise::Headers::WantDigest',
};

sub new
{
    my $this = shift( @_ );
    my $opts = {};
    $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
    my $self;
    # try-catch
    local $@;
    eval
    {
        $self = $this->SUPER::new( @_ );
    };
    if( $@ )
    {
        return( $this->error( "Error instantiating an HTTP::Promise::Headers object: $@" ) );
    }
    $self->{default_type} = undef;
    $self->{_init_strict_use_sub} = 1;
    $self->{_exception_class} = $EXCEPTION_CLASS;
    $self->debug( $opts->{debug} ) if( CORE::exists( $opts->{debug} ) );
    $self->{_ctype_cached} = '';
    return( $self );
}

# e.g. text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
sub accept
{
    my $self = shift( @_ );
    if( @_ )
    {
        my $types = $self->_get_args_as_array( @_ );
        $self->header( accept => $types );
        CORE::delete( $self->{acceptables} );
    }
    return( $self->_set_get_one( 'Accept' ) );
}

# Obsolete header that should not be used
sub accept_charset { return( shift->_set_get_one( 'Accept-Charset', @_ ) ); }

# e.g. gzip, deflate, br
sub accept_encoding { return( shift->_set_get_multi( 'Accept-Encoding', @_ ) ); }

# e.g.: en-GB,fr-FR;q=0.8,fr;q=0.6,ja;q=0.4,en;q=0.2
sub accept_language { return( shift->_set_get_multi( 'Accept-Language', @_ ) ); }

# NOTE: Accept-Patch is a response header
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Patch>
sub accept_patch { return( shift->_set_get_one( 'Accept-Patch', @_ ) ); }

# NOTE: Accept-Post is a response header
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Post>

lib/HTTP/Promise/Headers.pm  view on Meta::CPAN

sub etag { return( shift->_set_get_one( 'Etag', @_ ) ); }

sub exists
{
    my $self = shift( @_ );
    my $field = shift( @_ ) || return(0);
    my $rv = $self->header( $field );
    return( defined( $rv ) ? 1 : 0 );
}

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect>
sub expect { return( shift->_set_get_one( 'Expect', @_ ) ); }

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT>
sub expect_ct { return( shift->_set_get_multi( 'Expect-CT', @_ ) ); }

# NOTE: expires() is inherited
sub expires { return( shift->_date_header( 'Expires', @_ ) ); }

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers>
# e.g.: Access-Control-Expose-Headers: Content-Encoding, X-Kuma-Revision
sub expose_headers { return( shift->_set_get_multi( 'Access-Control-Expose-Headers', @_ ) ); }

# NOTE: flatten() is inherited

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded>
sub forwarded { return( shift->_set_get_one( 'Forwarded', @_ ) ); }

# NOTE: from() is inherited
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/From>
sub from { return( shift->_set_get_one( 'From', @_ ) ); }

sub get { return( shift->header( shift( @_ ) ) ); }

# NOTE: header() is inherited

# NOTE: header_field_names() is inherited

sub host { return( shift->_set_get_one( 'Host', @_ ) ); }

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match>
sub if_match { return( shift->_set_get_one( 'If-Match', @_ ) ); }

# NOTE: if_modified_since() is inherited
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since>
sub if_modified_since { return( shift->_date_header( 'If-Modified-Since', @_ ) ); }

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match>
sub if_none_match { return( shift->_set_get_one( 'If-None-Match', @_ ) ); }

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Range>
sub if_range { return( shift->_set_get_one( 'If-Range', @_ ) ); }

# NOTE: if_unmodified_since() is inherited
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Unmodified-Since>
sub if_unmodified_since { return( shift->_date_header( 'If-Unmodified-Since', @_ ) ); }

# NOTE: init_header() is inherited

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive>
sub keep_alive { return( shift->_set_get_one( 'Keep-Alive', @_ ) ); }

# NOTE: last_modified() is inherited
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified>
sub last_modified { return( shift->_date_header( 'Last-Modified', @_ ) ); }

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link>
sub link { return( shift->_set_get_multi( 'Link', @_ ) ); }

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location>
sub location { return( shift->_set_get_one( 'Location', @_ ) ); }

sub make_boundary
{
    my $self = shift( @_ );
    $self->_load_class( 'Data::UUID' ) || return( $self->pass_error );
    return( Data::UUID->new->create_str );
}

# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age>
sub max_age { return( shift->_set_get_number( 'Access-Control-Max-Age', @_ ) ); }

sub message
{
    my $self = shift( @_ );
    my $class = ref( $self ) || $self;
    no strict 'refs';
    if( $self->{verbose} || $self->{debug} || ${ $class . '::DEBUG' } )
    {
        my $r;
        if( $MOD_PERL )
        {
            # try-catch
            local $@;
            eval
            {
                $r = Apache2::RequestUtil->request;
            };
            if( $@ )
            {
                $stderr_raw->print( "Error trying to get the global Apache2::ApacheRec: $@\n" );
            }
        }

        my $ref;
        $ref = $self->message_check( @_ );
        return(1) if( !$ref );

        my $opts = {};
        $opts = pop( @$ref ) if( ref( $ref->[-1] ) eq 'HASH' );

        my $stackFrame = $self->message_frame( (caller(1))[3] ) || 1;
        $stackFrame = 1 unless( $stackFrame =~ /^\d+$/ );
        $stackFrame-- if( $stackFrame );
        $stackFrame++ if( ( (caller(1))[3] // '' ) eq 'HTTP::Promise::Headers::messagef' );
        my( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame );
        my $sub = ( caller( $stackFrame + 1 ) )[3] // '';
        my $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
        if( ref( $self->{_message_frame} ) eq 'HASH' )
        {
            if( exists( $self->{_message_frame}->{ $sub2 } ) )

lib/HTTP/Promise/Headers.pm  view on Meta::CPAN

See L<rfc7838, section 3|https://tools.ietf.org/html/rfc7838#section-3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc>

=head2 alternate_server

This is a convenience method for the header field C<Alt-Svc>.

To et it value, you provide a hash or hash reference of properties, including C<name> and C<value> respectively for the protocol-id and the alternate authority.

    $h->alternate_server( name => 'h2', value => ':443', ma => 2592000, persist => 1 );

would create the header value:

    Alt-Svc: h2=":443"; ma=2592000; persist=1

Without any parameter, it creates a new L<HTTP::Promise::Headers::AltSvc> object for each C<Alt-Svc> header value and returns an L<array object|Module::Generic::Array> of all those L<HTTP::Promise::Headers::AltSvc> objects.

=head2 authorization

    # Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
    $h->authorization( 'Basic YWxhZGRpbjpvcGVuc2VzYW1l' );

Sets or gets the C<Authorization> header field value. It takes a string value.

See also L</authorization_basic>

See L<rfc7235, section 4.2|https://tools.ietf.org/html/rfc7235#section-4.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization>

=head2 cache_control

    # Cache-Control: max-age=604800
    $h->cache_control( 'max-age=604800' );
    # Cache-Control: s-maxage=604800
    $h->cache_control( 's-maxage=604800' );
    # Cache-Control: no-cache
    $h->cache_control( 'no-cache' );
    # Cache-Control: max-age=604800, must-revalidate
    $h->cache_control( 'max-age=604800, must-revalidate' );
    # Cache-Control: public, max-age=604800, immutable
    $h->cache_control( 'public, max-age=604800, immutable' );

Sets or gets the C<Cache-Control> header field value. It takes either a string or an array or array reference of values.

See also L<HTTP::Promise::Headers::CacheControl> to have a more granular control.

See L<rfc7234, section 5.2|https://tools.ietf.org/html/rfc7234#section-5.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control>

=head2 clear_site_data

    # Clear-Site-Data: "cache", "cookies", "storage", "executionContexts"
    $h->clear_site_data( q{"cache", "cookies", "storage", "executionContexts"} );
    $h->clear_site_data( [qw( cache cookies storage executionContexts )] );

The Clear-Site-Data header accepts one or more directives. If all types of data should be cleared, the wildcard directive ("*") can be used.

See also L<HTTP::Promise::Headers::ClearSiteData> to have a more granular control.

See L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data>

=head2 connection

    # Connection: keep-alive
    # Connection: close

Sets or gets the C<Connection> header field value. It takes a string value.

See L<rfc7230, section 6.1|https://tools.ietf.org/html/rfc7230#section-6.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection>

=head2 content_disposition

    # Content-Disposition: inline
    # Content-Disposition: attachment
    # Content-Disposition: attachment; filename="filename.jpg"
    # Content-Disposition: form-data; name="fieldName"
    # Content-Disposition: form-data; name="fieldName"; filename="filename.jpg"

Sets or gets the C<Content-Disposition> header field value. It takes a string value.

See also L<HTTP::Promise::Headers::ContentDisposition> to have a more granular control.

See L<rfc6266, section 4|https://tools.ietf.org/html/rfc6266#section-4>, L<rfc7578, section 4.2|https://tools.ietf.org/html/rfc7578#section-4.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition...

=head2 content_encoding

    # Content-Encoding: gzip
    # Content-Encoding: compress
    # Content-Encoding: deflate
    # Content-Encoding: br

    # Multiple, in the order in which they were applied
    # Content-Encoding: deflate, gzip

Sets or gets the C<Cache-Encoding> header field value. It takes either a string or an array or array reference of values.

Encoding header fields and their nuances:

=over 4

=item C<Accept-Encoding>

The encodings accepted by the client.

=item C<Content-Encoding>

Contains the encodings that have been applied to the content, before transport

=item C<TE>

The encodings the user agent accepts.

=item C<Transfer-Encoding>

The encoding applied during transfer, such as C<chunked>

=back

See L<rfc7230, section 3.3.1|https://tools.ietf.org/html/rfc7230#section-3.3.1>:
"Unlike Content-Encoding (L<Section 3.1.2.1 of [RFC7231]|https://tools.ietf.org/html/rfc7231#section-3.1.2.1>), Transfer-Encoding is a property of the message, not of the representation"

See also L</accept_encoding>, L</transfer_encoding> and L</te> and this L<Stackoverflow discussion|https://stackoverflow.com/questions/11641923/transfer-encoding-gzip-vs-content-encoding-gzip>

See L<rfc7231, section 3.1.2.2|https://tools.ietf.org/html/rfc7231#section-3.1.2.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding>

lib/HTTP/Promise/Headers.pm  view on Meta::CPAN

See also L<rfc7230, section 5.4|https://tools.ietf.org/html/rfc7230#section-5.4> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host>

=head2 if_match

This sets or gets the C<If-Match> header value. It takes a string value.

For example:

    If-Match: "bfc13a64729c4290ef5b2c2730249c88ca92d82d"
    If-Match: "67ab43", "54ed21", "7892dd"
    If-Match: *

See also L<rfc7232, section 3.1|https://tools.ietf.org/html/rfc7232#section-3.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match>

=head2 if_modified_since

This sets or gets the C<If-Modified-Since> header value. It takes a date string value, a unix timestamp or a L<DateTime::Lite>, or a L<DateTime> value.

If no value is provided, it returns the current value of the C<Date> header field as a L<DateTime::Lite> object.

For example:

    If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT

See also L<rfc7232, section 3.3|https://tools.ietf.org/html/rfc7232#section-3.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since>

=head2 if_none_match

This sets or gets the C<If-None-Match> header value. It takes a string value.

For example:

    If-None-Match: "bfc13a64729c4290ef5b2c2730249c88ca92d82d"
    If-None-Match: W/"67ab43", "54ed21", "7892dd"
    If-None-Match: *

See also L<rfc7232, section 3.2|https://tools.ietf.org/html/rfc7232#section-3.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since>

=head2 if_range

This sets or gets the C<If-Range> header value. It takes a string value.

For example:

    If-Range: Wed, 21 Oct 2015 07:28:00 GMT

See also L<rfc7233, section 3.2|https://tools.ietf.org/html/rfc7233#section-3.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Range>

=head2 if_unmodified_since

This sets or gets the C<If-Unmodified-Since> header value. It takes a date string value, a unix timestamp or a L<DateTime::Lite>, or a L<DateTime> value.

If no value is provided, it returns the current value of the C<Date> header field as a L<DateTime::Lite> object.

For example:

    If-Unmodified-Since: Wed, 21 Oct 2015 07:28:00 GMT

See also L<rfc7232, section 3.4|https://tools.ietf.org/html/rfc7232#section-3.4> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Unmodified-Since>

=head2 keep_alive

This sets or gets the C<Keep-Alive> header value. It takes either a string or an array or array reference of properly formatted values.

See also L<HTTP::Promise::Headers::KeepAlive> to have a more granular control.

Example response containing a Keep-Alive header:

    HTTP/1.1 200 OK
    Connection: Keep-Alive
    Content-Encoding: gzip
    Content-Type: text/html; charset=utf-8
    Date: Thu, 11 Aug 2016 15:23:13 GMT
    Keep-Alive: timeout=5, max=1000
    Last-Modified: Mon, 25 Jul 2016 04:32:39 GMT
    Server: Apache

See also L<rfc7230, section A.1.2|https://tools.ietf.org/html/rfc7230#section-A.1.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive>

=head2 last_modified

This sets or gets the C<Last-Modified> header value. It takes a date string value, a unix timestamp or a L<DateTime::Lite>, or a L<DateTime> value.

If no value is provided, it returns the current value of the C<Date> header field as a L<DateTime::Lite> object.

For example:

    Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT

See also L<rfc7232, section 2.2|https://tools.ietf.org/html/rfc7232#section-2.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified>

=head2 link

This sets or gets the C<Link> header value. It takes a string value.

See also L<HTTP::Promise::Headers::Link> to have a more granular control.

Example:

    Link: <https://example.com>; rel="preconnect"

See also L<rfc8288, section 3|https://tools.ietf.org/html/rfc8288#section-3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link>

=head2 location

This sets or gets the C<Location> header value. It takes a string value.

Example:

    Location: /index.html

See also L<rfc7231, section 7.1.2|https://tools.ietf.org/html/rfc7231#section-7.1.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location>

=head2 max_age

This sets or gets the C<Location> header value. It takes a numeric value.

Example:

    Access-Control-Max-Age: 600



( run in 0.308 second using v1.01-cache-2.11-cpan-71847e10f99 )