Apache2-SSI

 view release on metacpan or  search on metacpan

lib/Apache2/SSI/URI.pm  view on Meta::CPAN

        path_info => $ref->{path_info},
        query_string => $ref->{query_string},
        _path_info_processed => 1,
        };
        my $tmp = $self->new_uri( $ref->{path_info} ? join( '', $ref->{path}, $ref->{path_info} ) : $ref->{path} );
        $tmp->query( $ref->{query_string} ) if( $ref->{query_string} );
        $hash->{document_uri} = $tmp;
        $self->{base_dir} = bless( $hash => ref( $self ) ) if( -d( $ref->{path} ) );
        $self->{base_uri} = bless( $hash => ref( $self ) );
    }
    return( $self->{base_uri} );
}

sub clone
{
    my $self = shift( @_ );
    my $new = {};
    my @fields = grep( !/^(apache_request|finfo)$/, keys( %$self ) );
    @$new{ @fields } = @$self{ @fields };
    $new->{apache_request} = $self->{apache_request};
    my $env = {};
    %$env = %{$self->{_env}};
    $new->{_env} = $env;
    return( bless( $new => ( ref( $self ) || $self ) ) );
}

sub code
{
    my $self = shift( @_ );
    my $r = $self->apache_request;
    if( $r )
    {
        $r->status( @_ ) if( @_ );
        return( $r->status );
    }
    else
    {
        $self->{code} = shift( @_ ) if( @_ );
        return( int( $self->{code} ) );
    }
}

sub document_dir { return( shift->document_directory( @_ ) ); }

sub document_directory
{
    my $self = shift( @_ );
    my $doc_path = $self->document_path || return( $self->error( "No document path set." ) );
    my $doc_root = $self->document_root || return( $self->error( "No document root set." ) );
    return( $self->make( document_uri => $doc_path ) ) if( -e( "${doc_root}${doc_path}" ) && -d( _ ) );
    my $parent = $self->parent;
    return( $parent );
}

sub document_filename { return( shift->filename( @_ ) ); }

sub document_path
{
    my $self = shift( @_ );
    my $class = ref( $self );
    my $caller = (caller(1))[3] // '';
    # my $caller = substr( $sub, rindex( $sub, ':' ) + 1 );
    my $r = $self->apache_request;
    if( $r )
    {
        if( @_ )
        {
            my $uri = shift( @_ );
            $r = $r->is_initial_req ? $r : $r->main;
            my $rr = $self->lookup_uri( $uri );
            if( !defined( $rr ) )
            {
                return;
            }
            my $u = APR::URI->parse( $rr->pool, $r->uri );
            # Remove trailing slash
            my $u2 = $self->_trim_trailing_slash( $u->rpath );
            $self->{document_path} = $u2;
            $self->{_uri_reset} = 'document_path' unless( $caller eq "${class}\::document_uri" );
        }
        elsif( !length( $self->{document_path} ) )
        {
            my $u = APR::URI->parse( $r->pool, $r->uri );
            $self->{document_path} = $self->new_uri( $u->rpath );
        }
    }
    else
    {
        if( @_ )
        {
            my $uri = shift( @_ );
            $self->{document_path} = $self->new_uri( $self->collapse_dots( $uri ) );
            $self->{_uri_reset} = 'document_path' unless( $caller eq "${class}\::document_uri" );
        }
    }
    return( $self->{document_path} );
}

sub document_root
{
    my $self = shift( @_ );
    my $r = $self->apache_request;
    my $new;
    if( @_ )
    {
        $new = shift( @_ );
        # unless( substr( $new, 0, 1 ) eq '/' )
        unless( File::Spec->file_name_is_absolute( $new ) )
        {
            $new = URI::file->new_abs( $new )->file( $^O );
        }
    }
    
    if( $r )
    {
        $r->document_root( $new ) if( defined( $new ) );
        $r->subprocess_env( DOCUMENT_ROOT => $r->document_root );
        return( $r->document_root );
    }
    else
    {

lib/Apache2/SSI/URI.pm  view on Meta::CPAN

    my $self = shift( @_ );
    # The user wants the entire hash reference
    unless( @_ )
    {
        my $r = $self->apache_request;
        if( $r )
        {
            # $r = $r->is_initial_req ? $r : $r->main;
            return( $r->subprocess_env )
        }
        else
        {
            unless( scalar( keys( %{$self->{_env}} ) ) )
            {
                $self->{_env} = {%ENV};
            }
            return( $self->{_env} );
        }
    }
    my $name = shift( @_ );
    return( $self->error( "No environment variable name was provided." ) ) if( !length( $name ) );
    my $opts = {};
    no warnings 'uninitialized';
    $opts = pop( @_ ) if( scalar( @_ ) && Scalar::Util::reftype( $_[-1] ) eq 'HASH' );
    # return( $self->error( "Environment variable value provided is a reference data (", overload::StrVal( $val ), ")." ) ) if( ref( $val ) && ( !overload::Overloaded( $val ) || ( overload::Overloaded( $val ) && !overload::Method( $val, '""' ) ) ) );
    my $r = $opts->{apache_request} || $self->apache_request;
    if( $r )
    {
        # $r = $r->is_initial_req ? $r : $r->main;
        $r->subprocess_env( $name => shift( @_ ) ) if( @_ );
        my $v = $r->subprocess_env( $name );
        return( $v );
    }
    else
    {
        my $env = {};
        unless( scalar( keys( %{$self->{_env}} ) ) )
        {
            # Make a copy of the environment variables
            $self->{_env} = {%ENV};
        }
        $env = $self->{_env};
        if( @_ )
        {
            $env->{ $name } = shift( @_ );
            my $meth = lc( $name );
            if( $self->can( $meth ) )
            {
                $self->$meth( $env->{ $name } );
            }
        }
        return( $env->{ $name } );
    }
}

# This is set by document_uri
sub filename
{
    my $self = shift( @_ );
    my $class = ref( $self );
    my $caller = (caller(1))[3] // '';
    # my $caller = substr( $sub, rindex( $sub, ':' ) + 1 );
    my $r = $self->apache_request;
    my $newfile;
    if( @_ )
    {
        $newfile = shift( @_ );
        return( $self->error( "New file provided, but it was an empty string." ) ) if( !defined( $newfile ) || !length( $newfile ) );
    }
    
    if( $r )
    {
        if( defined( $newfile ) )
        {
            $r = $r->is_initial_req ? $r : $r->main;
            my $rr = $r->lookup_file( $newfile );
            if( $rr->status == &Apache2::Const::HTTP_OK )
            {
                $newfile = $rr->filename;
            }
            else
            {
                $r->filename( $self->collapse_dots( $newfile, { separator => $DIR_SEP }) );
                # <https://perl.apache.org/docs/2.0/api/Apache2/RequestRec.html#toc_C_filename_>
                $r->finfo( APR::Finfo::stat( $newfile, &APR::Const::FINFO_NORM, $r->pool ) );
                $self->finfo( $newfile );
            }
            $r->subprocess_env( SCRIPT_FILENAME => $newfile );
            # Force to create new Apache2::SSI::URI object
            $self->{filename} = $newfile;
            $self->{_uri_reset} = 'filename' unless( $caller eq "${class}\::document_uri" );
        }
        elsif( !length( $self->{filename} ) )
        {
            $self->{filename} = $r->filename;
        }
    }
    else
    {
        if( defined( $newfile ) )
        {
            my $try = Cwd::realpath( $newfile );
            # Cwd::realpath would convert
            # Z:\perl\Apache2-SSI\t\htdocs\ssi\include.cgi
            # into 
            # Z:/perl/Apache2-SSI/t/htdocs/ssi/include.cgi
            # amazingly enough, so to make sure this keeps working on windows related platform, we need to call URI::file
            $newfile = URI::file->new( $try )->file( $^O ) if( defined( $try ) );
            unless( File::Spec->file_name_is_absolute( $newfile ) )
            {
                $newfile = URI::file->new_abs( $newfile )->file( $^O );
            }
            $self->env( SCRIPT_FILENAME => $newfile );
            $self->finfo( $newfile );
            # Force to create new Apache2::SSI::URI object
            # Either a URI object or an URI::file object
            $self->{filename} = $self->collapse_dots( $newfile, { separator => $DIR_SEP })->file( $^O );
            # Pass the file as new argument to URI::file which will create an object based on the value of the current OS
            # and transform it into a path à la linux, which is same as web, which is what we want
            # All this is unnecessary for linux type system or those who use / as directory separator,
            # but for windows type systems this is necessary

lib/Apache2/SSI/URI.pm  view on Meta::CPAN

        {
            $self->error( "An error occurred while creating URI object for \"$hdrs->{Location}\": $@" );
            return( $rr );
        }
        return( $rv );
    }   
    return( $rr );
}

sub make
{
    my $self = shift( @_ );
    return( $self->error( "Must be called with an existing object and not as ", __PACKAGE__, "->make()" ) ) if( !Scalar::Util::blessed( $self ) );
    my $p = $self->_get_args_as_hash( @_ );
    my $r = $self->apache_request;
    my $d = $self->document_root;
    my $b = $self->base_uri;
    my $f = $self->document_uri;
    $p->{apache_request} = $r if( !$p->{apache_request} && $r );
    $p->{document_root} = "$d" if( !$p->{document_root} && length( $d ) );
    $p->{base_uri} = "$b" if( !$p->{base_uri} && length( $b ) );
    $p->{document_uri} = "$f" if( !$p->{document_uri} );
    $p->{debug} = $self->debug if( !length( $p->{debug} ) );
    return( $self->new( $p ) );
}

sub new_uri
{
    my $self = shift( @_ );
    my $class = URI_CLASS;
    my $uri = shift( @_ );
    local $@;
    # try-catch
    my $rv = eval
    {
        return( $class->new( $uri ) );
    };
    if( $@ )
    {
        return( $self->error( "Unable to instantiate an URI object with \"$uri\": $@" ) );
    }
    return( $rv );
}

sub parent
{
    my $self = shift( @_ );
    my $path = $self->document_path;
    my $r = $self->apache_request;
    # I deliberately did not do split( '/', $path, -1 ) so that if there is a trailing '/', it will not be counted
    my @segments = $self->document_path->path_segments;
    pop( @segments );
    return( $self ) if( !scalar( @segments ) );
    return( $self->make( document_uri => join( '/', @segments ) ) );
}

sub path_info
{
    my $self = shift( @_ );
    my $class = ref( $self );
    my $caller = (caller(1))[3] // '';
    # my $caller = substr( $sub, rindex( $sub, ':' ) + 1 );
    my $r = $self->apache_request;
    if( $r )
    {
        if( @_ )
        {
            $r->path_info( shift( @_ ) );
            $self->_set_env( PATH_INFO => $r->path_info );
            $self->{_uri_reset} = 'path_info' unless( $caller eq "${class}\::document_uri" );
        }
        return( $r->path_info );
    }
    else
    {
        if( @_ )
        {
            $self->{path_info} = shift( @_ );
            $self->_set_env( PATH_INFO => $self->{path_info} );
            $self->{_uri_reset} = 'path_info' unless( $caller eq "${class}\::document_uri" );
        }
        return( $self->{path_info} );
    }
}

sub query_string
{
    my $self = shift( @_ );
    my $class = ref( $self );
    my $caller = (caller(1))[3] // '';
    # my $caller = substr( $sub, rindex( $sub, ':' ) + 1 );
    my $r = $self->apache_request;
    if( $r )
    {
        if( @_ )
        {
            my $qs = shift( @_ );
            $r->args( $qs );
            $self->_set_env( QUERY_STRING => $qs );
            $self->{_uri_reset} = 'query_string' unless( $caller eq "${class}\::document_uri" );
        }
        return( $r->args );
    }
    else
    {
        if( @_ )
        {
            $self->{query_string} = shift( @_ );
            $self->_set_env( QUERY_STRING => $self->{query_string} );
            $self->{_uri_reset} = 'query_string' unless( $caller eq "${class}\::document_uri" );
        }
        return( $self->{query_string} );
    }
}

sub root
{
    my $self = shift( @_ );
    return( $self->{root} ) if( $self->{root} );
    my $hash = 
    {
    code => 200,
    document_uri => $self->new_uri( '/' ),
    document_root => $self->document_root,
    debug => $self->debug,
    path_info => '',
    query_string => '',
    _path_info_processed => 1,
    };
    $hash->{document_path} = $hash->{document_uri};
    $hash->{apache_request} = $self->apache_request if( $self->apache_request );
    my $root = bless( $hash => ref( $self ) );
    # Scalar::Util::weaken( $copy );
    $root->{base_dir} = $root;
    $root->{base_uri} = $root;
    $self->{root} = $root;
    return( $root );
}

# shortcut
sub uri { return( shift->document_uri( @_ ) ); }

# Path info works as a path added to a document uri, such as:
# /my/doc.html/path/info
# But we need to distinguish with missing document hierarchy inside a directory, such as:
# /my/folder/missing_doc.html/path/info
# otherwise we would be treating /missing_doc.html/path/info as a path info
sub _find_path_info
{
    my $self = shift( @_ );



( run in 2.858 seconds using v1.01-cache-2.11-cpan-fe3c2283af0 )