Apache2-API

 view release on metacpan or  search on metacpan

lib/Apache2/API/Request.pm  view on Meta::CPAN

    use APR::Pool ();
    use APR::Request ();
    use APR::Socket ();
    use APR::SockAddr ();
    use APR::Request::Cookie;
    use APR::Request::Apache2;
    # For subnet_of() method
    use APR::IpSubnet ();
    use Apache2::API::Request::Params;
    use Apache2::API::Request::Upload;
    use Apache2::API::DateTime;
    use Apache2::API::Query;
    use Apache2::API::Status;
    use Cookie::Jar;
    use DateTime::Lite;
    use Encode ();
    use File::Which ();
    use HTTP::AcceptLanguage;
    use JSON ();
    use Module::Generic::HeaderValue;
    use Scalar::Util;
    use URI;
    use URI::Escape;
    our $VERSION = 'v0.4.2';
    our( $SERVER_VERSION, $ERROR );
};

use strict;
use warnings;

my $methods_bit_to_name =
{
    Apache2::Const::M_GET()        => 'GET',
    Apache2::Const::M_POST()       => 'POST',
    Apache2::Const::M_PUT()        => 'PUT',
    Apache2::Const::M_DELETE()     => 'DELETE',
    Apache2::Const::M_OPTIONS()    => 'OPTIONS',
    Apache2::Const::M_TRACE()      => 'TRACE',
    Apache2::Const::M_CONNECT()    => 'CONNECT',
    (Apache2::Const->can('M_PATCH')       ? (Apache2::Const::M_PATCH()       => 'PATCH')       : ()),
    (Apache2::Const->can('M_PROPFIND')    ? (Apache2::Const::M_PROPFIND()    => 'PROPFIND')    : ()),
    (Apache2::Const->can('M_PROPPATCH')   ? (Apache2::Const::M_PROPPATCH()   => 'PROPPATCH')   : ()),
    (Apache2::Const->can('M_MKCOL')       ? (Apache2::Const::M_MKCOL()       => 'MKCOL')       : ()),
    (Apache2::Const->can('M_COPY')        ? (Apache2::Const::M_COPY()        => 'COPY')        : ()),
    (Apache2::Const->can('M_MOVE')        ? (Apache2::Const::M_MOVE()        => 'MOVE')        : ()),
    (Apache2::Const->can('M_LOCK')        ? (Apache2::Const::M_LOCK()        => 'LOCK')        : ()),
    (Apache2::Const->can('M_UNLOCK')      ? (Apache2::Const::M_UNLOCK()      => 'UNLOCK')      : ()),
};

my $json_ctypes_re = qr{\Aapplication/(?:[a-zA-Z][\w\-]+\+)?json\z}i;

sub init
{
    my $self = shift( @_ );
    my $r;
    $r = shift( @_ ) if( @_ % 2 );
    $self->{request} = $r;
    $self->{checkonly} = 0;
    $self->SUPER::init( @_ ) || return( $self->pass_error );
    $r ||= $self->{request};
    $self->{accept_charset}     = undef;
    $self->{auth}               = undef;
    $self->{charset}            = undef;
    $self->{client_api_version} = undef;
    $self->{_server_version}    = undef;
    # Which is an Apache2::Request, but inherits everything from Apache2::RequestRec and APR::Request::Apache2
    unless( $self->{checkonly} )
    {
        return( $self->error( "No Apache2::RequestRec was provided." ) ) if( !$r );
        return( $self->error( "Apache2::RequestRec provided ($r) is not an object!" ) ) if( !Scalar::Util::blessed( $r ) );
        return( $self->error( "I was expecting an Apache2::RequestRec, but instead I got \"$r\"." ) ) if( !$r->isa( 'Apache2::RequestRec' ) );
        $self->{request} = $r;
        # Important as few other methods rely on this
        $self->{apr} = APR::Request::Apache2->handle( $r );
        my $headers = $self->headers;
        # rfc 6750 <https://tools.ietf.org/html/rfc6750>
        my $auth = $headers->{Authorization};
        $self->auth( $auth ) if( length( $auth ) );
        # Content-Type: application/json; charset=utf-8
        my $ctype_raw = $self->content_type;
        # Accept: application/json; version=1.0; charset=utf-8
        my $accept_raw = $self->accept;
        # Returns an array of Module::Generic::HeaderValue objects
        my $accept_all = $self->acceptables;
        my( $ctype_def, $ctype );

        if( defined( $ctype_raw ) && CORE::length( $ctype_raw // '' ) )
        {
            $ctype_def = Module::Generic::HeaderValue->new_from_header( $ctype_raw );
            $ctype = lc( $ctype_def->value->first // '' );
            $self->type( $ctype );
            my $enc = $ctype_def->param( 'charset' );
            $self->charset( $enc ) if( defined( $enc ) && length( $enc ) );
        }

        if( defined( $accept_all ) && !$accept_all->is_empty )
        {
            my $accept_def = $accept_all->first;
            $self->accept_type( $accept_def->value->first );
            $self->client_api_version( $accept_def->param( 'version' ) );
            $self->accept_charset( $accept_def->param( 'charset' ) );
        }

        my $json    = $self->json->utf8;
        my $payload = $self->data;
        # An error occurred while reading the payload, because even empty, data would return an empty string.
        return( $self->pass_error ) if( !defined( $payload ) );
        if( defined( $ctype ) && 
            $ctype =~ $json_ctypes_re && 
            CORE::length( $payload ) )
        {
            my $json_data = '';
            # try-catch
            local $@;
            eval
            {
                $json_data = $json->decode( $payload );
            };
            if( $@ )
            {
                $r->log_error( ref( $self ), "::init() JSON data provided is malformed: $@" );
                return( $self->error({ code => Apache2::Const::HTTP_BAD_REQUEST, message => "JSON data provided is malformed." }) );
            }
            $self->payload( $json_data );
        }
    }
    return( $self );
}

# Tells whether the connection has been aborted or not
sub aborted { return( shift->_try( 'connection', 'aborted' ) ); }

# e.g. text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
sub accept { return( shift->headers->{ 'Accept' } ); }

sub accept_charset { return( shift->_set_get_scalar( 'accept_charset', @_ ) ); }

# e.g. gzip, deflate, br
sub accept_encoding { return( shift->headers->{ '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->headers->{ 'Accept-Language' } ); }

sub accept_type { return( shift->_set_get_scalar( 'accept_type', @_ ) ); }

sub accept_version { return( shift->client_api_version( @_ ) ); }

sub acceptable
{
    my $self = shift( @_ );
    if( @_ )
    {
        my $ref = scalar( @_ ) == 1
            ? Scalar::Util::reftype( $_[0] ) eq 'ARRAY'
                ? shift( @_ )
                : [ @_ ]
            : [ @_ ];
        $self->{acceptable} = $self->new_array( $ref );
    }
    if( !$self->{acceptable} )
    {
        my $all = $self->acceptables;
        my $list = [];
        for( @$all )
        {
            push( @$list, $_->value->first );
        }
        $self->{acceptable} = $self->new_array( $list );
    }
    return( $self->{acceptable} );
}

sub acceptables
{
    my $self = shift( @_ );
    return( $self->{acceptables} ) if( $self->{acceptables} );
    my $accept_raw = $self->accept;
    if( $accept_raw )
    {
        $self->_load_class( 'Module::Generic::HeaderValue' ) || return( $self->pass_error );
        # Typical value from Ajax call: application/json, text/javascript, */*
        my $all = Module::Generic::HeaderValue->new_from_multi( $accept_raw ) ||
            return( $self->pass_error( Module::Generic::HeaderValue->error ) );
        $self->{acceptables} = $all;
    }
    return( $self->{acceptables} );
}

# The allowed methods, GET, POST, PUT, OPTIONS, HEAD, etc
sub allowed { return( shift->_try( 'request', 'allowed', @_ ) ); }

sub allow_methods { return( shift->_try( 'request', 'allow_methods', @_ ) ); }

sub allow_methods_list
{
    my $self = shift( @_ );

lib/Apache2/API/Request.pm  view on Meta::CPAN


# APR::Request::Apache2->handle( $r );
sub apr { return( shift->_set_get_object( { field => 'apr', no_init => 1 }, 'APR::Request', @_ ) ); }

# sub args { return( shift->_try( 'request', 'args', @_ ) ); }
# Better yet, use APR::Body->args
sub args { return( shift->_try( 'apr', 'args', @_ ) ); }

sub args_status { return( shift->_try( 'args_status', 'args', @_ ) ); }

sub as_string { return( shift->_try( 'request', 'as_string' ) ); }

sub auth { return( shift->_set_get_scalar( 'auth', @_ ) ); }

sub auth_headers { return( shift->_try( 'request', 'note_auth_failure', @_ ) ); }

sub auth_headers_basic { return( shift->_try( 'request', 'note_basic_auth_failure', @_ ) ); }

sub auth_headers_digest { return( shift->_try( 'request', 'note_digest_auth_failure', @_ ) ); }

sub auth_name { return( shift->_try( 'request', 'auth_name', @_ ) ); }

# with mod_perl2, we need to call ap_auth_type() rather than auth_type()
sub auth_type { return( shift->_try( 'request', 'ap_auth_type', @_ ) ); }

sub authorization { return( shift->headers( 'Authorization', @_ ) ); }

# Must manually update the counter
# $r->connection->keepalives($r->connection->keepalives + 1);
# See Apache2::RequestRec
sub auto_header 
{
    my $self = shift( @_ );
    if( @_ )
    {
        my $v = shift( @_ );
        return( $self->request->assbackwards( $v ? 0 : 1 ) );
    }
    return( $self->request->assbackwards );
}

# my( $rc, $passwd ) = $req->basic_auth_passwd;
sub basic_auth_passwd { return( shift->_try( 'request', 'get_basic_auth_pw' ) ); }

{
    no warnings 'once';
    *basic_auth_pwd = \&basic_auth_passwd;
    *basic_auth_pw = \&basic_auth_passwd;
}

# See APR::Request
# sub body { return( shift->_try( 'request', 'body', @_ ) ); }
sub body { return( shift->_try( 'apr', 'body', @_ ) ); }

sub body_status { return( shift->_try( 'apr', 'body_status', @_ ) ); }

sub brigade_limit { return( shift->_try( 'apr', 'brigade_limit', @_ ) ); }

sub call { return( shift->_try( 'request', @_ ) ); }

sub charset { return( shift->_set_get_scalar( 'charset', @_ ) ); }

sub checkonly { return( shift->_set_get_scalar( 'checkonly', @_ ) ); }

sub child_terminate { return( shift->_try( 'request', 'child_terminate' ) ); }

sub client_api_version
{
    my $self = shift( @_ );
    if( @_ )
    {
        my $v = shift( @_ );
        unless( ref( $v ) eq 'version' )
        {
            $v = version->parse( $v );
        }
        $self->{client_api_version} = $v;
    }
    return( $self->{client_api_version} );
}

# Close the client connection
# APR::Socket->close is not implemented; left undone
# So this is a successful work around
sub close
{
    my $self = shift( @_ );
    # Using APR::Socket to get the fileno
    my $fd = $self->socket->fileno;
    require IO::File;
    my $sock = IO::File->new;
    if( $sock->fdopen( $fd, 'w' ) )
    {
        return( $sock->close );
    }
    else
    {
        return(0);
    }
}

sub code { return( shift->_try( 'request', 'status', @_ ) ); }

# Apache2::Connection
sub connection { return( shift->_try( 'request', 'connection' ) ); }

sub connection_id { return( shift->_try( 'connection', 'id' ) ); }

sub content { return( ${ shift->request->slurp_filename } ); }

sub content_encoding { return( shift->_try( 'request', 'content_encoding', @_ ) ); }

sub content_languages { return( shift->_try( 'request', 'content_languages', @_ ) ); }

sub content_length { return( shift->headers( 'Content-Length' ) ); }

sub content_type
{
    my $self = shift( @_ );
    my $ct = $self->headers( 'Content-Type' );
    return( $ct ) if( !scalar( @_ ) );

lib/Apache2/API/Request.pm  view on Meta::CPAN


        # $r->read( $payload, $nbytes );
        my $to_read = int( $nbytes );
        my $read    = 0;
        # try-catch
        local $@;

        while( $read < $to_read )
        {
            my $chunk = '';
            my $want  = $to_read - $read;
            # Cap chunk size
            $want     = 65536 if( $want > 65536 );
            my $n = eval{ $r->read( $chunk, $want ); };
            # APR::Error
            if( $@ )
            {
                return( $self->error( "Error trying to read $want bytes from the APR::Bucket: $@" ) );
            }
            # EOF/abort
            last unless( $n );
            $payload .= $chunk;
            $read    += $n;
        }
    }
    # No Content-Length: stream until read() returns 0
    elsif( defined( $ctype ) && 
           lc( $ctype ) eq 'application/json' )
    {
        my $total = 0;
        while(1)
        {
            # try-catch
            local $@;
            my $chunk = '';
            my $n = eval{ $r->read( $chunk, 8192 ); };
            # APR::Error
            if( $@ )
            {
                return( $self->error( "Error trying to read 8192 bytes from the APR::Bucket: $@" ) );
            }
            last unless( $n );
            $payload .= $chunk;
            $total   += $n;

            if( $max_size && $total > $max_size )
            {
                return( $self->error({
                    code    => Apache2::Const::HTTP_REQUEST_ENTITY_TOO_LARGE,
                    message => "Total payload submitted ($total bytes) exceeds configured limit ($max_size)."
                }) );
            }
        }
    }

    # try-catch
    local $@;
    eval
    {
        # This is set during the init() phase
        my $charset = $self->charset;
        if( defined( $charset ) && $charset )
        {
            $payload = Encode::decode( $charset, $payload, Encode::FB_CROAK );
        }
        # We only UTF-8 decode it if it is a pure text file.
        # If no $ctype is defined, the default should be application/octet-stream
        elsif( defined( $ctype ) && $ctype =~ m,^text/,i )
        {
            $payload = Encode::decode_utf8( $payload, Encode::FB_CROAK );
        }
    };
    if( $@ )
    {
        return( $self->error({
            code    => Apache2::Const::HTTP_BAD_REQUEST,
            message => "Error while decoding payload received from http client: $@"
        }) );
    }
    # Cache the request body so other handlers can access it too.
    $self->pnotes( REQUEST_BODY => $payload );
    $self->pnotes( REQUEST_BODY_PROCESSED => 1 );
    return( $payload );
}

sub datetime { return( Apache2::API::DateTime->new( debug => shift->debug ) ); }

sub decode
{
    my $self = shift( @_ );
    return( APR::Request::decode( shift( @_ ) ) );
}

sub discard_request_body { return( shift->_try( 'request', 'discard_request_body' ) ); }

# Do not track: 1 or 0
sub dnt { return( shift->env( 'HTTP_DNT', @_ ) ); }

sub document_root { return( shift->_try( 'request', 'document_root', @_ ) ); }

sub document_uri { return( shift->env( 'document_uri', @_ ) ); }

sub encode
{
    my $self = shift( @_ );
    return( APR::Request::encode( shift( @_ ) ) );
}

sub env
{
    my $self = shift( @_ );
    my $r = $self->request;
    if( @_ )
    {
        if( scalar( @_ ) == 1 )
        {
            my $v = shift( @_ );
            if( ref( $v ) eq 'HASH' )
            {
                foreach my $k ( sort( keys( %$v ) ) )
                {
                    $r->subprocess_env( $k => $v->{ $k } );
                }
            }

lib/Apache2/API/Request.pm  view on Meta::CPAN


# NOTE: str2datetime for compatibility
sub str2datetime { return( shift->datetime->str2datetime( @_ ) ); }

# NOTE: str2time for compatibility
sub str2time { return( shift->datetime->str2time( @_ ) ); }

sub subnet_of
{
    my $self = shift( @_ );
    my( $ip, $mask ) = @_;
    my $ipsub;
    # try-catch
    local $@;
    my $error;
    eval
    {
        if( $ip && $mask )
        {
            $ipsub = APR::IpSubnet->new( $self->pool, $ip, $mask );
        }
        elsif( $ip )
        {
            $ipsub = APR::IpSubnet->new( $self->pool, $ip );
        }
        else
        {
            $error = "No ip address or block was provided to evaluate current ip against";
        }
    };
    return( $self->error( $error ) ) if( defined( $error ) );
    if( $@ )
    {
        return( $self->error( "An error occurred while trying to create a APR::IpSubnet object with ip \"$ip\" and mask \"$mask\": $@" ) );
    }
    return( $ipsub->test( $self->remote_addr ) );
}

sub subprocess_env { return( shift->_try( 'request', 'subprocess_env' ) ); }

sub temp_dir { return( shift->_try( 'apr', 'temp_dir', @_ ) ); }

sub the_request { return( shift->_try( 'request', 'the_request' ) ); }

# NOTE: time2datetime for compatibility
sub time2datetime { return( shift->datetime->time2datetime( @_ ) ); }

# NOTE: time2str for compatibility
sub time2str { return( shift->datetime->time2str( @_ ) ); }

sub type
{
    my $self = shift( @_ );
    if( @_ )
    {
        # Something like text/html, text/plain or application/json, etc...
        $self->{type} = shift( @_ );
    }
    elsif( !CORE::length( $self->{type} ) )
    {
        # Content-Type: application/json; charset=utf-8
        my $ctype_raw = $self->content_type;
        if( defined( $ctype_raw ) )
        {
            my $ctype_def = Module::Generic::HeaderValue->new_from_header( $ctype_raw ) ||
                return( $self->pass_error( Module::Generic::HeaderValue->error ) );
            # Accept: application/json; version=1.0; charset=utf-8
            my $ctype = lc( $ctype_def->value->first // '' );
            $self->{type} = $ctype if( $ctype );
            my $enc = $ctype_def->param( 'charset' );
            $enc = lc( $enc ) if( defined( $enc ) );
            $self->charset( $enc );
        }
    }
    return( $self->{type} );
}

sub unparsed_uri
{
    my $self = shift( @_ );
    my $uri = $self->uri;
    my $unparseed_path = $self->request->unparsed_uri;
    my $unparsed_uri = URI->new( $uri->scheme . '://' . $uri->host_port . $unparseed_path );
    return( $unparsed_uri );
}

sub uploads
{
    my $self = shift( @_ );
    my $r = Apache2::API::Request::Params->new( $self->request );
    my( @uploads ) = $r->upload;
    my $objs = $self->new_array;
    foreach my $name ( @uploads )
    {
        my $up = $r->upload( $name );
        if( !$up )
        {
            CORE::warn( "Error: could not get the Apache2::API::Params::Upload object for this upload field \"$name\".\n" );
        }
        else
        {
            CORE::push( @$objs, $up );
        }
    }
    return( $objs );
}

#sub uri { return( URI->new( shift->request->uri( @_ ) ) ); }
# FYI, there is also the APR::URI module, but I could not see the value of it
# https://perl.apache.org/docs/2.0/api/APR/URI.html
sub uri
{
    my $self = shift( @_ );
    my $r = $self->request;
    # my $host = $r->get_server_name;
    my $host = $r->hostname;
    my $port = $r->get_server_port;
    my $proto = ( $port == 443 ) ? 'https' : 'http';
    my $path = $r->unparsed_uri;
    # The port is superfluous, and even annoying
    # return( URI->new( "${proto}://${host}:${port}${path}" ) );
    return( URI->new( "${proto}://${host}${path}" ) );
}

sub url_decode { return( shift->decode( @_ ) ); }

sub url_encode { return( shift->encode( @_ ) ); }

sub user { return( shift->_try( 'request', 'user' ) ); }

sub user_agent { return( shift->headers->{ 'User-Agent' } ); }

lib/Apache2/API/Request.pm  view on Meta::CPAN

        @rv = eval
        {
            return( $self->$pack->$meth() ) if( !scalar( @_ ) );
            return( $self->$pack->$meth( @_ ) );
        };
    }
    else
    {
        $rv = eval
        {
            return( $self->$pack->$meth() ) if( !scalar( @_ ) );
            return( $self->$pack->$meth( @_ ) );
        };
    }
    if( $@ )
    {
        return( $self->error( "An error occurred while trying to call Apache ", ucfirst( $pack ), " method \"$meth\": $@" ) );
    }
    return( wantarray() ? @rv : $rv );
}

# NOTE: sub FREEZE is inherited

sub STORABLE_freeze { CORE::return( CORE::shift->FREEZE( @_ ) ); }

sub STORABLE_thaw { CORE::return( CORE::shift->THAW( @_ ) ); }

# NOTE: sub THAW is inherited

1;
# NOTE: POD
__END__

=encoding utf8

=head1 NAME

Apache2::API::Request - Apache2 Incoming Request Access and Manipulation

=head1 SYNOPSIS

    use Apache2::API::Request;
    # $r is the Apache2::RequestRec object
    my $req = Apache2::API::Request->new( request => $r, debug => 1 );
    # or, to test it outside of a modperl environment:
    my $req = Apache2::API::Request->new( request => $r, debug => 1, checkonly => 1 );

    # Tells whether the connection has been aborted or not
    $req->aborted;

    # e.g.: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    my $accept = $req->accept;

    # Returns an array object
    my $all = $req->acceptable;
    $req->acceptable( $array_ref );

    # Returns an array object
    my $all = $req->acceptables;

    my $charset = $req->accept_charset;

    # e.g.: gzip, deflate, br
    my $encoding = $req->accept_encoding;

    # en-GB,fr-FR;q=0.8,fr;q=0.6,ja;q=0.4,en;q=0.2
    my $lang = $req->accept_language;

    my $type = $req->accept_type;

    my $version = $req->accept_version;

    # GET, POST, PUT, OPTIONS, HEAD, etc
    my $methods = $req->allowed;

    # get an APR::Request::Apache2 object
    my $apr = $req->apr;

    # query string as an hash reference
    my $hash_ref = $req->args; # also an APR::Request::Param::Table object

    my $status = $req->args_status;

    # HTTP query
    my $string = $req->as_string;

    my $auth = $req->auth;
    my $auth = $req->authorization;
    my $auth_type = $req->auth_type;

    $req->auto_header(1);

    # returns an APR::Request::Param::Table object similar to APR::Table
    my $body = $req->body;

    my $status = $req->body_status;

    my $limit = $req->brigade_limit;

    my $charset = $req->charset;

    $req->child_terminate;

    my $api_version = $req->client_api_version;

    # close client connection
    $req->close;

    my $status_code = $req->code;

    # Apache2::Connection
    my $conn = $req->connection;
    my $id = $req->connection_id;

    # content of the request filename
    my $content = $req->content;

    my $encoding = $req->content_encoding;

    my $langs_array_ref = $req->content_languages;

    my $len = $req->content_length;

    # text/plain
    my $ct = $req->content_type;

    # Get a Cookie object
    my $cookie = $req->cookie( $name );
    # Cookie::Jar object
    my $jar = $req->cookies;

    # get data string sent by client
    my $data = $req->data;

    my $formatter = $req->datetime;
    my $decoded = $req->decode( $string );

    my $do_not_track = $req->dnt;

    my $encoded = $req->encode( $string );

    $req->discard_request_body(1);

    my $document_root = $req->document_root;
    my $url = $req->document_uri;
    # APR::Table object
    my $hash_ref = $req->env;
    my $headers = $req->err_headers_out;
    # request filename
    my $filename = $req->filename;
    # APR::Finfo object
    my $finfo = $req->finfo;
    # e.g.: CGI/1.1
    my $gateway = $req->gateway_interface;
    my $code_ref = $req->get_handlers( $name );

    # 404 Not Found
    my $str = $req->get_status_line(404);
    my $r = $req->global_request;
    my $is_head = $req->header_only;

lib/Apache2/API/Request.pm  view on Meta::CPAN

    my $agent = $req->user_agent;

=head1 VERSION

    v0.4.2

=head1 DESCRIPTION

The purpose of this module is to provide an easy access to various methods designed to process and manipulate incoming requests.

This is designed to work under modperl.

Normally, one would need to know which method to access across various Apache2 mod perl modules, which makes development more time consuming and even difficult, because of the scattered documentation and even sometime outdated.

This module alleviate this problem by providing all the necessary methods in one place. Also, at the contrary of L<Apache2> modules suit, all the methods here are die safe. When an error occurs, it will always return undef() and the error will be abl...

For its alter ego to manipulate outgoing HTTP response, use the L<Apache2::API::Response> module.

Throughout this documentation, we refer to C<$r> as the L<Apache request object|Apache2::RequestRec> and C<$req> as an object from this module.

=head1 CONSTRUCTORS

=head2 new

This takes an optional hash or hash reference of options and instantiate a new object.

It takes the following parameters:

=over 4

=item * C<checkonly>

If true, it will not perform the initialisation it would usually do under modperl.

=item * C<debug>

Optional. If set with a positive integer, this will activate verbose debugging message

=item * C<max_size>

Optional. This is the maximum size of the data that can be sent to us over HTTP. By default, there is no limit.

=item * C<request>

This is a required parameter to be sent with a value set to a L<Apache2::RequestRec> object

=back

=head1 METHODS

=head2 aborted

Tells whether the connection has been aborted or not, by calling L<Apache2::Connection/aborted>

=head2 accept

Returns the HTTP C<Accept> header value, such as C<text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8>

See also L</headers>

=head2 accept_charset

Sets or gets the acceptable character set. This is computed upon object instantiation by looking at the C<Accept> header:

    Accept: application/json; version=1.0; charset=utf-8

Here, it would be C<utf-8>

=head2 accept_encoding

Returns the HTTP C<Accept-Encoding> header value.

    Accept-Encoding: gzip, deflate;q=1.0, *;q=0.5
    Accept-Encoding: gzip, deflate, br

See also L</headers> and L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding>

=head2 accept_language

Returns the HTTP C<Accept-Language> header value such as C<en-GB,fr-FR;q=0.8,fr;q=0.6,ja;q=0.4,en;q=0.2>

See also L</headers>

=head2 accept_type

Sets or gets the acceptable content type. This is computed upon object instantiation by looking at the C<Accept> header:

    Accept: application/json; version=1.0; charset=utf-8

Here, it would be C<application/json>

=head2 accept_version

Sets or gets the version of the api being queried. This is computed upon object instantiation by looking at the C<Accept> header:

    Accept: application/json; version=1.0; charset=utf-8

Here, it would be C<1.0>

=head2 acceptable

This method parse the request header C<Accept>, by calling L</acceptables>, which could be, for example:

    application/json, text/javascript, */*

And return an L<array object|Module::Generic::Array> of acceptable content types.

    my $all = $req->acceptable;
    my $first = $req->acceptable->first;

You can also sets its array reference by passing either a list of value or an array reference.

=head2 acceptables

This takes the value from the C<Accept> header, splits them using L<Module::Generic::HeaderValue/new_from_multi> and returns an L<array object|Module::Generic::Array> of L<Module::Generic::HeaderValue> objects with their L<value|Module::Generic::Head...

So, if the C<Accept> header value was C<application/json, text/javascript, */*>, the array object returned would contain 3 L<Module::Generic::HeaderValue> objects with each C<< $hdr->value->first >> method returning:

=over 4

=item 1. C<application/json>

=item 2. C<text/javascript>

=item 3. C<*/*>

=back

=head2 allowed

Gets or sets the allowed methods bitmask such as GET, POST, PUT, OPTIONS, HEAD, etc, by calling L<Apache2::RequestRec/allowed>

It returns a bitvector of the allowed methods.

For example, if the module can handle only C<GET> and C<POST> methods it could start with:

    use Apache2::API;
    unless( $r->method_number == Apache2::Const::M_GET || 
            $r->method_number == Apache2::Const::M_POST )
    {
        $r->allowed( $r->allowed | ( 1 << Apache2::Const::M_GET ) | ( 1 << Apache2::Const::M_POST ) );
        return( Apache2::Const::HTTP_METHOD_NOT_ALLOWED );
    }

See also L</allowed_methods>

=head2 allow_methods

    $req->allow_methods( $reset );
    $req->allow_methods( $reset, @methods );

Provided with a reset boolean and a list of HTTP methods, and this will set the allowed methods such as GET, POST, PUT, OPTIONS, HEAD, etc, by calling L<Apache2::Access/allow_methods>

If the reset boolean passed is a true value, then all the previously allowed methods are removed, otherwise they are left unchanged.

For example, to allow only C<GET> and C<POST>, notwithstanding what was set previously:

lib/Apache2/API/Request.pm  view on Meta::CPAN


=head2 basic_auth_pwd

This is an alias for L</basic_auth_passwd>

=head2 body

Returns an L<APR::Request::Param::Table|APR::Request::Param> object containing the C<POST> data parameters of the L<Apache2::Request> object.

    my $body = $req->body;
    my @body_names = $req->body;

If there is no request body, then this would return C<undef>. So, for example, if you do a C<POST> query without any content, this would return C<undef>

An optional name parameter can be passed to return the POST (or other similar query types) data parameter associated with the given name:

    my $foo_body = $req->body("foo");

In scalar context this method fetches the first matching body param.  In list context it returns all matching body params.

This is similar to the C<param> method. The main difference is that modifications to the scalar C<< $req->body() >> table affect the underlying C<apr_table_t> attribute in C<apreq_request_t>, so their impact will be noticed by all C<libapreq2> applic...

Contrary to perl hash, this uses L<APR::Table> and the order in the hash is preserved, so you could do:

    my @body_names = $req->body;
    my @body_names = %$body;

would yield the same thing.

This will throw an L<APR::Request::Error> object whenever L</body_status> returns a non-zero value.

Check L<Apache2::Request> and L<APR::Table> for more information.

=head2 body_status

    my $int = $req->body_status; # should return 0

Returns the final status code of the body parser.

=head2 brigade_limit

    my $int = $req->brigade_limit;
    $req->brigade_limit( $int );

Get or set the brigade_limit for the current parser. This limit determines how many bytes of a file upload that the parser may spool into main memory. Uploads exceeding this limit are written directly to disk.

See also L</temp_dir>

=head2 call

Provided with an Apache2 API method name, and optionally with some additional arguments, and this will call that Apache2 method and return its result.

This is designed to allow you to call arbitrary Apache2 method that, possibly, are not covered here.

For example:

    my $bitmask = $req->call( 'allow_override_opts' );

It returns whatever value this call returns.

=head2 charset

Returns the charset, if any, found in the HTTP request received and processed upon initialisation of this module object.

So for example, if the HTTP request C<Content-type> is

    Content-Type: application/json; charset=utf-8

Then, L</charset> would return C<utf-8>

See also L</type> to retrieve only the content type, i.e without other information such as charset.

See also L</client_api_version> which would contain the requested api version, if any.

See also L<charset> for the charset provided, if any. For example C<utf-8>

=head2 checkonly

This is also an object initialisation property.

If true, this will discard the normal processing of incoming HTTP request under modperl.

This is useful and intended when testing this module offline.

=head2 child_terminate

Terminate the current worker process as soon as the current request is over, by calling L<Apache2::RequestRec/child_terminate>

This is not supported in threaded MPMs.

See L<Apache2::RequestUtil> for more information.

=head2 client_api_version

Returns the client api version requested, if provided. This is set during the object initialisation phase.

An example header to require api version C<1.0> would be:

    Accept: application/json; version=1.0; charset=utf-8

In this case, this would return C<1.0>

=head2 close

This close the client connection, by calling L<Apache2::Connection/socket>, which returns a L<APR::Socket>

This is not implemented in by L<APR::Socket>, so this is an efficient work around.

If the socket is writable, it is closed and returns the value from closing it, otherwise returns C<0>

However, a word of caution, you most likely do not need or want to close manually the client connection and instea have your method return Apache2::Const::OK or any other constant matching the HTTP code you want to return.

=head2 code

Sets or gets the response status code, by calling L<Apache2::RequestRec/status>

From the L<Apache2::RequestRec> documentation:

Usually you will set this value indirectly by returning the status code as the handler's function result. However, there are rare instances when you want to trick Apache into thinking that the module returned an C<Apache2::Const::OK> status code, but...

    $req->status( $some_code );
    return( Apache2::Const::OK );

=head2 connection

Returns a L<Apache2::Connection> object.

=head2 connection_id

Returns the connection id; unique at any point in time by calling L<Apache2::Connection/id>.

See L<Apache2::Connection> for more information.

=head2 content

Returns the content of the file specified with C<< $req->filename >>. It calls L<Apache2::RequestRec/slurp_filename>, but instead of returning a scalar reference, which L<Apache2::RequestRec/slurp_filename> does, it returns the data itself.

See L</slurp_filename> to get a scalar reference instead.

=head2 content_encoding

Returns the value of the C<Content-Encoding> HTTP response header.

See also L</headers>

=head2 content_languages

    my $array_ref = $req->content_languages();
    my $array_ref = $req->content_languages( $array_reference );

Sets or gets the value of the C<Content-Language> HTTP header, by calling L<Apache2::RequestRec/content_languages>

Content languages are string like C<en> or C<fr>.

If a new value is provided, it must be an array reference of language codes.

It returns the language codes as an array reference.

=head2 content_length

Returns the length in byte of the request body, by getting the header C<Content-Length> value.

See also L</headers>

=head2 content_type

Retrieves the value of the C<Content-type> header value. See L<Apache2::RequestRec> for more information.

For example:

    application/json; charset=utf-8

See also L</type> to retrieve only the content type, i.e without other information such as charset.

See also L</client_api_version> which would contain the requested api version, if any.

See also L<charset> for the charset provided, if any. For example C<utf-8>

=head2 cookie

Returns the current value for the given cookie name, which may be C<undef> if nothing is found.

This works by calling the L</cookies> method, which returns a L<cookie jar object|Cookie::Jar>.

=head2 cookies

Returns a L<Cookie::Jar> object acting as a jar with various methods to access, manipulate and create cookies.

=head2 data

This method reads the data sent by the client. It can be used as an accessor, and it will return a cached data, if any, or read the data from L<APR::Bucket>, or it can be used as a mutator to artificially set a payload.

Internally it uses L<Apache2::RequestUtil/pnotes> to cache the processed request body and stores it in C<REQUEST_BODY>, and set the shared property C<REQUEST_BODY_PROCESSED> to C<1>. Thus, the processed raw request body is always for other handlers w...

It takes an optional hash or hash reference of the following options:

=over 4

=item * C<data>

When provided, this will set the request body to the value provided.

=item * C<max_size>

The maximum size of the data that can be transmitted to us over HTTP. By default, there is no limit.

=back

Finally, if a charset is specified, this will also decode it from its encoded charset into perl internal utf8.

This is specifically designed for C<JSON> payload.

It returns a string of data upon success, or sets an L<error|Module::Generic/error> and return C<undef> or an empty list depending on the context.

You can also set a maximum size to read by setting the attribute C<PAYLOAD_MAX_SIZE> in Apache configuration file.

For example:

    <Directory /home/john/www>
        PerlOptions +GlobalRequest
        SetHandler modperl
        # package inheriting from Apache2::API
        PerlResponseHandler My::API
        # 2Mb upload limit
        PerlSetVar PAYLOAD_MAX_SIZE 2097152
    </Directory>

This is just an example and not a recommandation. Your mileage may vary.

=head2 datetime

Returns a new L<Apache2::API::DateTime> object, which is used to parse and format dates for HTTP.

See L<Apache2::API/parse_datetime> and L<Apache2::API/format_datetime>

=head2 decode

Given a url-encoded string, this returns the decoded string, by calling L<APR::Request/decode>

This uses L<APR::Request> XS method.

See also L<rfc3986|https://datatracker.ietf.org/doc/html/rfc3986>

=head2 discard_request_body

    my $rc = $req->discard_request_body;

In C<HTTP/1.1>, any method can have a body. However, most C<GET> handlers would not know what to do with a request body if they received one. This helper routine tests for and reads any message body in the request, simply discarding whatever it recei...

Returns C<Apache2::Const::OK> upon success.

    use Apache2::API;
    my $rc = $req->discard_request_body;
    return( $rc ) if( $rc != Apache2::Const::OK );

This method calls L<Apache2::RequestIO/discard_request_body>

=head2 dnt

Sets or gets the environment variable C<HTTP_DNT> using L<Apache2::RequestRec/subprocess_env>. See L</env> below for more on that.

This is an abbreviation for C<Do not track>

If available, typical value is a boolean such as C<0> or C<1>

=head2 document_root

Sets or retrieve the document root for this server.

lib/Apache2/API/Request.pm  view on Meta::CPAN

From the L<Apache2::RequestRec> documentation:

When called in void context with no arguments, it populate C<%ENV> with special variables (e.g. C<$ENV{QUERY_STRING}>) like mod_cgi does.

When called in a non-void context with no arguments, it returns an C<APR::Table object>.

When the $key argument (string) is passed, it returns the corresponding value (if such exists, or C<undef>. The following two lines are equivalent:

     $val = $req->subprocess_env( $key );
     $val = $req->subprocess_env->get( $key );

When the $key and the $val arguments (strings) are passed, the value is set. The following two lines are equivalent:

     $req->subprocess_env( $key => $val );
     $req->subprocess_env->set( $key => $val );

The C<subprocess_env> C<table> is used by L<Apache2::SubProcess>, to pass environment variables to externally spawned processes. It is also used by various Apache modules, and you should use this table to pass the environment variables. For example i...

      $req->subprocess_env( MyLanguage => "de" );

you can then deploy C<mod_include> and write in C<.shtml> document:

      <!--#if expr="$MyLanguage = en" -->
      English
      <!--#elif expr="$MyLanguage = de" -->
      Deutsch
      <!--#else -->
      Sorry
      <!--#endif -->

=head2 temp_dir

    my $dir = $req->temp_dir;
    $req->temp_dir( $dir );

Get or set the spool directory for uploads which exceed the configured brigade_limit.

=head2 the_request

    my $request = $req->the_request();
    my $old_request = $req->uri( $new_request );

Get or set the first HTTP request header as a string by calling L<Apache2::RequestRec/the_request>. For example:

    GET /foo/bar/my_path_info?args=3 HTTP/1.0

=head2 time2datetime

Alias to L<Apache2::API::DateTime/time2datetime>

=head2 time2str

Alias to L<Apache2::API::DateTime/time2str>

=head2 type

Returns the content type of the request received. This value is set at object initiation phase.

So for example, if the HTTP request C<Content-type> is

    Content-Type: application/json; charset=utf-8

Then, L</type> would return C<application/json>

=head2 unparsed_uri

The URI without any parsing performed.

If for example the request was:

     GET /foo/bar/my_path_info?args=3 HTTP/1.0

C<< $req->uri >> returns:

     /foo/bar/my_path_info

whereas C<< $req->unparsed_uri >> returns:

     /foo/bar/my_path_info?args=3

=head2 uploads

Returns an L<array object|Module::Generic::Array> of L<Apache2::API::Request::Upload> objects.

=head2 uri

Returns a L<URI> object representing the full uri of the request.

This is different from the original L<Apache2::RequestRec> which only returns the path portion of the URI.

So, to get the path portion using our L</uri> method, one would simply do C<< $req->uri->path() >>

This L<URI> object is built using L<Apache2::RequestUtil/get_server_name> for the C<host>, L<Apache2::RequestUtil/get_server_port> for the port number, and the scheme is C<https> if the port is C<443>, otherwise C<http>. It is followed then by the pa...

=head2 url_decode

This is merely a convenient pointer to L</decode>

=head2 url_encode

This is merely a convenient pointer to L</encode>

=head2 user

Get the user name, if an authentication process was successful. Or set it, by calling L<Apache2::RequestRec/user>

For example, let's print the username passed by the client:

     my( $res, $sent_pw ) = $req->get_basic_auth_pw;
     return( $res ) if( $res != Apache2::Const::OK );
     print( "User: ", $req->user );

=head2 user_agent

Returns the user agent, ie the browser signature as provided in the request headers received under the HTTP header C<User-Agent>

=head2 _find_bin( string )

Given a binary, this will search for it in the path.

=head2 _try( object type, method name, @_ )



( run in 2.184 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )