Apache2-API
view release on metacpan or search on metacpan
lib/Apache2/API/Response.pm view on Meta::CPAN
# -*- perl -*-
##----------------------------------------------------------------------------
## Apache2 API Framework - ~/lib/Apache2/API/Response.pm
## Version v0.2.0
## Copyright(c) 2025 DEGUEST Pte. Ltd.
## Author: Jacques Deguest <jack@deguest.jp>
## Created 2023/05/30
## Modified 2025/11/02
## All rights reserved
##
##
## This program is free software; you can redistribute it and/or modify it
## under the same terms as Perl itself.
##----------------------------------------------------------------------------
package Apache2::API::Response;
BEGIN
{
use strict;
use warnings;
warnings::register_categories( 'Apache2::API' );
use parent qw( Module::Generic );
use vars qw( $VERSION );
use Apache2::Request;
use Apache2::Const -compile => qw( :common :http );
use Apache2::Log ();
use Apache2::Response ();
use Apache2::RequestIO ();
use Apache2::RequestRec ();
use Apache2::SubRequest ();
use APR::Request ();
# use APR::Request::Cookie;
use Apache2::API::Status;
use Cookie::Jar;
use Scalar::Util;
use URI::Escape ();
our $VERSION = 'v0.2.0';
};
use strict;
use warnings;
sub init
{
my $self = shift( @_ );
my $r;
$r = shift( @_ ) if( @_ % 2 );
# Which is an Apache2::Request, but inherits everything from Apache2::RequestRec and APR::Request::Apache2
$self->{request} = '';
$self->{checkonly} = 0;
$self->SUPER::init( @_ );
$r ||= $self->{request};
unless( $self->{checkonly} )
{
return( $self->error( "No Apache2::API::Request was provided." ) ) if( !$r );
return( $self->error( "Apache2::API::Request provided ($r) is not an object!" ) ) if( !Scalar::Util::blessed( $r ) );
return( $self->error( "I was expecting an Apache2::API::Request, but instead I got \"$r\"." ) ) if( !$r->isa( 'Apache2::API::Request' ) );
}
return( $self );
}
# Response header: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials>
sub allow_credentials { return( shift->_set_get_one( 'Access-Control-Allow-Credentials', @_ ) ); }
# Response header <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers>
sub allow_headers { return( shift->_set_get_one( 'Access-Control-Allow-Headers', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods>
sub allow_methods { return( shift->_set_get_one( 'Access-Control-Allow-Methods', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin>
sub allow_origin { return( shift->_set_get_one( 'Access-Control-Allow-Origin', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc>
sub alt_svc { return( shift->_set_get_multi( 'Alt-Svc', @_ ) ); }
sub bytes_sent { return( shift->_try( '_request', 'bytes_sent' ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control>
sub cache_control { return( shift->_set_get_one( 'Cache-Control', @_ ) ); }
sub call { return( shift->_try( 'request', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data>
sub clear_site_data { return( shift->_set_get_multi( 'Clear-Site-Data', @_ ) ); }
# Apache2::Connection
sub connection { return( shift->_try( '_request', 'connection' ) ); }
# Set the http code to be returned, e.g,:
# return( $resp->code( Apache2::Const:HTTP_OK ) );
sub code { return( shift->_try( '_request', 'status', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition>
# TODO: More work to be done here like create a disposition method to parse its content
sub content_disposition { return( shift->_set_get_one( 'Content-Disposition', @_ ) ); }
# sub content_encoding { return( shift->_request->content_encoding( @_ ) ); }
sub content_encoding
{
my $self = shift( @_ );
my( $pack, $file, $line ) = caller;
my $sub = ( caller( 1 ) )[3];
# try-catch
local $@;
my $rv = eval
{
return( $self->_request->content_encoding( @_ ) );
};
if( $@ )
{
return( $self->error( "An error occurred while trying to access Apache Request method \"content_encoding\": $@" ) );
}
return( $rv );
}
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language
sub content_language { return( shift->headers( 'Content-Language', @_ ) ); }
sub content_languages { return( shift->_try( '_request', 'content_languages', @_ ) ); }
# sub content_length { return( shift->headers( 'Content-Length', @_ ) ); }
# https://perl.apache.org/docs/2.0/api/Apache2/Response.html#toc_C_set_content_length_
sub content_length { return( shift->_try( '_request', 'set_content_length', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Location>
sub content_location { return( shift->_set_get_one( 'Content-Location', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range>
sub content_range { return( shift->_set_get_one( 'Content-Range', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy>
sub content_security_policy { return( shift->_set_get_one( 'Content-Security-Policy', @_ ) ); }
sub content_security_policy_report_only { return( shift->_set_get_one( 'Content-Security-Policy-Report-Only', @_ ) ); }
# Apache content_type method is special. It does not just set the content type
sub content_type { return( shift->_try( '_request', 'content_type', @_ ) ); }
# sub content_type { return( shift->headers( 'Content-Type', @_ ) ); }
sub cookie_new
{
my $self = shift( @_ );
my $opts = $self->_get_args_as_hash( @_ );
return( $self->error( "Cookie name was not provided." ) ) if( !$opts->{name} );
# No value is ok to remove a cookie, but it needs to be an empty string, not undef
# return( $self->error( "No value was provided for cookie \"$opts->{name}\"." ) ) if( !length( $opts->{value} ) && !defined( $opts->{value} ) );
my $c = $self->request->cookies->make( $opts ) || return( $self->pass_error( $self->request->cookies->error ) );
return( $c );
}
# Add or replace a cookie, but because the headers function of Apache2 is based on APR::Table
# there is no replace method, AND because the value of the headers is a string and not an object
# we have to crawl each already set cookie, parse them, compare them en replace them or add them
sub cookie_replace
{
my $self = shift( @_ );
my $cookie = shift( @_ ) || return( $self->error( "No cookie to add to outgoing headers was provided." ) );
# Expecting an APR::Request::Cookie object
return( $self->error( "Cookie provided (", ref( $cookie ), ") is not an object." ) ) if( !Scalar::Util::blessed( $cookie ) );
return( $self->error( "Cookie object provided (", ref( $cookie ), ") does not seem to have an \"as_string\" method." ) ) if( !$cookie->can( 'as_string' ) );
# We use err_headers_out() which makes it also possible to set cookies upon error (regular headers_out method cannot)
my( @cookie_headers ) = $self->err_headers->get( 'Set-Cookie' );
if( !scalar( @cookie_headers ) )
{
$self->err_headers->set( 'Set-Cookie' => $cookie->as_string );
}
else
{
my $jar = Cookie::Jar->new;
# Check each cookie header set to see if ours is one of them
my $found = 0;
for( my $i = 0; $i < scalar( @cookie_headers ); $i++ )
{
my $c = $jar->extract_one( $cookie_headers[ $i ] ) || do
{
warn( "Error parsing cookie string '", $cookie_headers[ $i ], "': ", $jar->error, "\n" ) if( $self->_is_warnings_enabled( 'Apache2::API' ) );
next;
};
if( $c->name eq $cookie->name )
{
$cookie_headers[ $i ] = $cookie->as_string;
$found = 1;
}
}
if( !$found )
{
$self->err_headers->add( 'Set-Cookie' => $cookie->as_string );
}
else
{
# Remove all Set-Cookie headers
$self->err_headers->unset( 'Set-Cookie' );
# Now, re-add our updated set
foreach my $cookie_str ( @cookie_headers )
{
$self->err_headers->add( 'Set-Cookie' => $cookie_str );
}
}
}
return( $cookie );
}
sub cookie_set
{
my $self = shift( @_ );
my $cookie = shift( @_ ) || return( $self->error( "No cookie to add to outgoing headers was provided." ) );
# Expecting an APR::Request::Cookie object
return( $self->error( "Cookie provided (", ref( $cookie ), ") is not an object." ) ) if( !Scalar::Util::blessed( $cookie ) );
return( $self->error( "Cookie object provided (", ref( $cookie ), ") does not seem to have an \"as_string\" method." ) ) if( !$cookie->can( 'as_string' ) );
$self->err_headers->set( 'Set-Cookie' => $cookie->as_string );
return( $cookie );
}
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy>
sub cross_origin_embedder_policy { return( shift->_set_get_one( 'Cross-Origin-Embedder-Policy', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy>
sub cross_origin_opener_policy { return( shift->_set_get_one( 'Cross-Origin-Opener-Policy', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy>
sub cross_origin_resource_policy { return( shift->_set_get_one( 'Cross-Origin-Resource-Policy', @_ ) ); }
sub cspro { return( shift->content_security_policy_report_only( @_ ) ); }
# e.g. custom_response( $status, $string );
# e.g. custom_response( Apache2::Const::AUTH_REQUIRED, "Authenticate please" );
# package MyApache2::MyShop;
# use Apache2::Response ();
# use Apache2::Const -compile => qw(FORBIDDEN OK);
# sub access {
# my $r = shift;
#
# if (MyApache2::MyShop::tired_squirrels()) {
# $r->custom_response(Apache2::Const::FORBIDDEN,
# "It is siesta time, please try later");
# return Apache2::Const::FORBIDDEN;
# }
#
# return Apache2::Const::OK;
# }
sub custom_response { return( shift->_try( '_request', 'custom_response', @_ ) ); }
sub decode
{
my $self = shift( @_ );
return( APR::Request::decode( shift( @_ ) ) );
}
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Digest>
sub digest { return( shift->_set_get_one( 'Digest', @_ ) ); }
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 ) ) )
{
lib/Apache2/API/Response.pm view on Meta::CPAN
# <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 meets_conditions { return( shift->_try( '_request', 'meets_conditions' ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/NEL>
sub nel { return( shift->_set_get_one( 'NEL', @_ ) ); }
# This adds the following to the outgoing headers:
# Pragma: no-cache
# Cache-control: no-cache
sub no_cache { return( shift->_try( '_request', 'no_cache', @_ ) ); }
sub no_local_copy { return( shift->_try( '_request', 'no_local_copy', @_ ) ); }
sub print { return( shift->_try( '_request', 'print', @_ ) ); }
sub printf { return( shift->_try( '_request', 'printf', @_ ) ); }
sub puts { return( shift->_try( '_request', 'puts', @_ ) ); }
sub redirect
{
my $self = shift( @_ );
# I have to die if nothing was provided, because our return value is the http code. We can't just return undef()
my $uri = shift( @_ ) || die( "No uri provided to redirect\n" );
# Stringify
$self->headers->set( 'Location' => "$uri" );
$self->code( Apache2::Const::HTTP_MOVED_TEMPORARILY );
return( Apache2::Const::HTTP_MOVED_TEMPORARILY );
}
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy>
sub referrer_policy { return( shift->_set_get_one( 'Referrer-Policy', @_ ) ); }
sub request { return( shift->_set_get_object( 'request', 'Apache2::API::Request', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After>
sub retry_after { return( shift->_set_get_one( 'Retry-After', @_ ) ); }
sub rflush { return( shift->_try( '_request', 'rflush' ) ); }
# e.g. send_cgi_header( $buffer )
sub send_cgi_header { return( shift->_try( '_request', 'send_cgi_header', @_ ) ); }
# e.g. sendfile( $filename );
# sendfile( $filename, $offset );
# sendfile( $filename, $offset, $len );
sub sendfile { return( shift->_try( '_request', 'sendfile', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server>
sub server { return( shift->_set_get_one( 'Server', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>
sub server_timing { return( shift->_set_get_one( 'Server-Timing', @_ ) ); }
# e.g set_content_length( 1024 )
sub set_content_length { return( shift->_try( '_request', 'set_content_length', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie>
sub set_cookie { return( shift->_set_get_one( 'Set-Cookie', @_ ) ); }
sub set_etag { return( shift->_try( '_request', 'set_etag', @_ ) ); }
sub set_keepalive { return( shift->_try( '_request', 'set_keepalive', @_ ) ); }
# <https://perl.apache.org/docs/2.0/api/Apache2/Response.html#toc_C_set_last_modified_>
sub set_last_modified { return( shift->_try( '_request', 'set_last_modified', @_ ) ); }
# Returns a APR::Socket
# See Apache2::Connection manual page
sub socket { return( shift->_try( 'connection', 'client_socket', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/SourceMap>
sub sourcemap { return( shift->_set_get_one( 'SourceMap', @_ ) ); }
sub status { return( shift->_try( '_request', 'status', @_ ) ); }
sub status_line { return( shift->_try( '_request', 'status_line', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security>
sub strict_transport_security { return( shift->_set_get_one( 'Strict-Transport-Security', @_ ) ); }
sub subprocess_env { return( shift->_try( '_request', 'subprocess_env' ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin>
sub timing_allow_origin { return( shift->_set_get_multi( 'Timing-Allow-Origin', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer>
sub trailer { return( shift->_set_get_one( 'Trailer', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding>
sub transfer_encoding { return( shift->_set_get_one( 'Transfer-Encoding', @_ ) ); }
sub unescape { return( URI::Escape::uri_unescape( @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade>
sub upgrade { return( shift->_set_get_multi( 'Upgrade', @_ ) ); }
sub update_mtime { return( shift->_try( '_request', 'update_mtime', @_ ) ); }
sub uri_escape { return( shift->escape( @_ ) ); }
sub uri_unescape { return( shift->unescape( @_ ) ); }
sub url_decode { return( shift->decode( @_ ) ); }
sub url_encode { return( shift->encode( @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary>
sub vary { return( shift->_set_get_multi( 'Vary', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Via>
sub via { return( shift->_set_get_multi( 'Via', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Want-Digest>
sub want_digest { return( shift->_set_get_multi( 'Want-Digest', @_ ) ); }
# <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Warning>
sub warning { return( shift->_set_get_one( 'Warning', @_ ) ); }
lib/Apache2/API/Response.pm view on Meta::CPAN
# Access-Control-Expose-Headers
my $expose_headers = $resp->expose_headers;
$resp->flush;
my $msg = $resp->get_http_message( 429 => 'ja_JP' );
my $string = $resp->get_status_line;
my $content_type = $resp->headers( 'Content-Type' );
# or (since it is case insensitive)
my $content_type = $resp->headers( 'content-type' );
# or
my $content_type = $resp->headers->{'Content-Type'};
$resp->header( 'Content-Type' => 'text/plain' );
# or
$resp->headers->{'Content-Type'} = 'text/plain';
# APR::Table object
my $headers = $resp->headers;
my $headers = $resp->headers_out;
$resp->internal_redirect( $uri );
$resp->internal_redirect_handler( $uri );
my $rv = $resp->is_info(100);
my $rv = $resp->is_success(200);
my $rv = $resp->is_redirect(302);
my $rv = $resp->is_error(400);
my $rv = $resp->is_client_error(401);
my $rv = $resp->is_server_error(500);
# Keep-Alive
my $keep_alive = $resp->keep_alive;
# Last-Modified
my $http_date = $resp->last_modified;
# Last-Modified-Date
my $http_date = $resp->last_modified_date;
# The number of bytes sent. Actually calls bytes_sent()
my $nbytes = $resp->length;
# Location
my $loc = $resp->location;
my $rv = $resp->lookup_uri( $uri );
my $etag = $resp->make_etag( $force_weak );
# Access-Control-Max-Age
my $max_age = $resp->max_age;
my $rv = $resp->meets_conditions;
# NEL
my $nel = $resp->nel;
$resp->no_cache(1);
$resp->no_local_copy(1);
$resp->print( @some_data );
$resp->printf( $template, $param1, $param2 );
my $puts = $resp->puts;
my $rv = $resp->redirect( $uri );
# Referrer-Policy
my $policy = $resp->referrer_policy;
my $r = $resp->request;
# Retry-After
my $retry_after = $resp->retry_after;
$resp->rflush;
$resp->send_cgi_header;
$resp->sendfile( $filename, $offset, $len );
$resp->sendfile( $filename );
# Server
my $server = $resp->server;
my $server_timing = $resp->server_timing;
$resp->set_content_length(1024);
# Set-Cookie
$resp->set_cookie( $cookie );
$resp->set_last_modified;
$resp->set_keepalive(1);
my $socket = $resp->socket;
my $sourcemap = $resp->sourcemap;
my $status = $resp->status;
my $status_line = $resp->status_line;
# Strict-Transport-Security
my $policy = $resp->strict_transport_security;
# APR::Table object
my $env = $resp->subprocess_env;
# Timing-Allow-Origin
my $origin = $resp->timing_allow_origin;
# Trailer
my $trailerv = $resp->trailer;
my $enc = $resp->transfer_encoding;
my $unescape = $resp->unescape( $string );
# Upgrade
my $upgrade = $resp->upgrade;
$resp->update_mtime( $seconds );
my $uri = $resp->uri_escape( $uri );
my $uri = $resp->uri_unescape( $uri );
my $decoded = $resp->url_decode( $uri );
my $encoded = $resp->url_encode( $uri );
# Vary
my $vary = $resp->vary;
# Via
my $via = $resp->via;
# Want-Digest
my $want = $resp->want_digest;
# Warning
my $warn = $resp->warning;
$resp->write( $buffer, $len, $offset );
# WWW-Authenticate
my $auth = $resp->www_authenticate;
# X-Content-Type-Options
my $opt = $resp->x_content_type_options;
# X-DNS-Prefetch-Control
my $proto = $resp->x_dns_prefetch_control;
# X-Frame-Options
my $opt = $resp->x_frame_options;
# X-XSS-Protection
my $xss = $resp->x_xss_protection;
=head1 VERSION
v0.2.0
=head1 DESCRIPTION
The purpose of this module is to provide an easy access to various method to process and manipulate incoming request.
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 C<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...
Fo its alter ego to manipulate outgoing HTTP response, use the L<Apache2::API::Response> module.
lib/Apache2/API/Response.pm view on Meta::CPAN
=head2 content_language
Sets or gets the HTTP header field C<Content-Language>
=head2 content_languages
my $languages = $resp->content_languages();
my $prev_lang = $resp->content_languages( $nev_lang );
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>.
It returns the language codes as an array reference.
=head2 content_length
Set the content length for this request, by calling L<Apache2::Response/set_content_length>
See L<Apache2::Response> for more information.
=head2 content_location
Sets or gets the HTTP header field C<Content-Location>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Location>
=head2 content_range
Sets or gets the HTTP header field C<Content-Range>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range>
=head2 content_security_policy
Sets or gets the HTTP header field C<Content-Security-Policy>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy>
=head2 content_security_policy_report_only
Sets or gets the HTTP header field C<Content-Security-Policy-Report-Only>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only>
=head2 content_type
Get or set the HTTP response C<Content-type> header value.
For example, set the C<Content-type> header to C<text/plain>.
$resp->content_type('text/plain');
If you set this header via the C<headers_out> table directly, it will be ignored by Apache. So do not do that.
See L<Apache2::RequestRec> for more information.
=head2 cookie_new
Given a hash reference with the following properties, this will create a L<Cookie> object that can be stringified and aded into a C<Set-Cookie> HTTP header.
=over 4
=item C<name>
=item C<value>
=item C<domain>
=item C<expires>
=item C<http_only>
=item C<max_age>
=item C<path>
=item C<secure>
=item C<same_site>
=back
See L<Cookie::Jar/make> and L<Cookie> for more information on those parameters.
=head2 cookie_replace
Given a cookie object, this either sets the given cookie in a C<Set-Cookie> header or replace the existing one with the same cookie name, if any.
It returns the cookie object provided.
=head2 cookie_set
Given a cookie object, this set the C<Set-Cookie> HTTP header for this cookie.
However, it does not check if another C<Set-Cookie> header exists for this cookie.
=head2 cross_origin_embedder_policy
Sets or gets the HTTP header field C<Cross-Origin-Embedder-Policy>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy>
=head2 cross_origin_opener_policy
Sets or gets the HTTP header field C<Cross-Origin-Opener-Policy>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy>
=head2 cross_origin_resource_policy
Sets or gets the HTTP header field C<Cross-Origin-Resource-Policy>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy>
=head2 cspro
Alias for L</content_security_policy_report_only>
=head2 custom_response
Install a custom response handler for a given status.
$resp->custom_response( $status, $string );
The first argument is the status for which the custom response should be used (e.g. C<Apache2::Const::AUTH_REQUIRED>)
The second argument is the custom response to use. This can be a static string, or a URL, full or just the uri path (C</foo/bar.txt>).
B<custom_response>() does not alter the response code, but is used to replace the standard response body. For example, here is how to change the response body for the access handler failure:
package MyApache2::MyShop;
use Apache2::Response ();
use Apache2::Const -compile => qw(FORBIDDEN OK);
sub access {
my $r = shift;
if (MyApache2::MyShop::tired_squirrels()) {
$resp->custom_response(Apache2::Const::FORBIDDEN,
"It is siesta time, please try later");
return Apache2::Const::FORBIDDEN;
}
return Apache2::Const::OK;
}
...
# httpd.conf
PerlModule MyApache2::MyShop
<Location /TestAPI__custom_response>
AuthName dummy
AuthType none
PerlAccessHandler MyApache2::MyShop::access
PerlResponseHandler MyApache2::MyShop::response
</Location>
When squirrels cannot run any more, the handler will return C<403>, with the custom message:
It is siesta time, please try later
=head2 decode
Given a url-encoded string, this returns the decoded string
This uses L<APR::Request> XS method.
=head2 digest
Sets or gets the HTTP header field C<Digest>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Digest>
=head2 encode
Given a string, this returns its url-encoded version
This uses L<APR::Request> XS method.
=head2 env
my $val = $resp->env( $name );
$resp->env( $name, $value );
Using the Apache C<subprocess_env> table, this sets or gets environment variables. This is the equivalent of this:
$resp->subprocess_env;
$env_table = $resp->subprocess_env;
$resp->subprocess_env( $key => $val );
$val = $resp->subprocess_env( $key );
where C<$resp> is this module object.
If one argument is provided, it will return the corresponding environment value.
If one or more sets of key-value pair are provided, they are set accordingly.
If nothing is provided, it returns a L<APR::Table> object.
=head2 err_headers
Given one or more name => value pair, this will set them in the HTTP header using the L</err_headers_out> method.
=head2 err_headers_out
Get or sets HTTP response headers, which are printed out even on errors and persist across internal redirects.
According to the L<Apache2::RequestRec> documentation:
The difference between L</headers_out> (L<Apache2::RequestRec/headers_out>) and L</err_headers_out> (L<Apache2::RequestRec/err_headers_out>), is that the latter are printed even on error, and persist across internal redirects (so the headers printed ...
For example, if a handler wants to return a C<404> response, but nevertheless to set a cookie, it has to be:
$resp->err_headers_out->add( 'Set-Cookie' => $cookie );
return( Apache2::Const::NOT_FOUND );
If the handler does:
$resp->headers_out->add( 'Set-Cookie' => $cookie );
return( Apache2::Const::NOT_FOUND );
the C<Set-Cookie> header will not be sent.
See L<Apache2::RequestRec> for more information.
=head2 escape
Provided with a value and this will return it uri escaped by calling L<URI::Escape/uri_escape>.
=head2 etag
Sets or gets the HTTP header field C<Etag>
=head2 expires
Sets or gets the HTTP header field C<Expires>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires>
=head2 expose_headers
Sets or gets the HTTP header field C<Access-Control-Expose-Headers>
e.g.: Access-Control-Expose-Headers: Content-Encoding, X-Kuma-Revision
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers>
=head2 flush
Flush any buffered data to the client, by calling L<Apache2::RequestIO/rflush>
$resp->flush();
Unless STDOUT stream's C<$|> is false, data sent via C<< $resp->print() >> is buffered. This method flushes that data to the client.
For example if your script needs to perform a relatively long-running operation (e.g. a slow db lookup) and the client may timeout if it receives nothing right away, you may want to start the handler by setting the C<Content-Type> header, following b...
$resp->content_type('text/html');
$resp->flush; # send the headers out
$resp->print( long_operation() );
return( Apache2::Const::OK );
[1] mod_perl2 documentation L<https://perl.apache.org/docs/2.0/user/coding/coding.html#toc_Forcing_HTTP_Response_Headers_Out>
=head2 get_http_message
Given an HTTP code integer, and optionally a language code, this returns the HTTP status message in the language given.
If no language is provided, this returns the message by default in C<en_GB>, i.e. British English.
See also L<Apache2::API::Status>
=head2 get_status_line
Return the C<Status-Line> for a given status code (excluding the HTTP-Version field), by calling L<Apache2::RequestRec/status_line>
For example:
print( $resp->get_status_line( 400 ) );
will print:
lib/Apache2/API/Response.pm view on Meta::CPAN
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After>
=head2 rflush
Flush any buffered data to the client, by calling L<Apache2::RequestIO/rflush>
Unless STDOUT stream's C<$|> is false, data sent via C<< $resp->print() >> is buffered. This method flushes that data to the client.
It does not return any value.
=head2 send_cgi_header
Parse the header, by calling L<Apache2::Response/send_cgi_header>
$resp->send_cgi_header( $buffer );
This method is really for back-compatibility with mod_perl 1.0. It is very inefficient to send headers this way, because of the parsing overhead.
If there is a response body following the headers it will be handled too (as if it was sent via L</print>).
Notice that if only HTTP headers are included they will not be sent until some body is sent (again the C<send> part is retained from the mod_perl 1.0 method).
See L<Apache2::Response> for more information.
=head2 sendfile
Provided with a file path, an optional offset and an optional length, and this will send a file or a part of it, by calling L<Apache2::RequestIO/sendfile>
$rc = $resp->sendfile( $filename );
$rc = $resp->sendfile( $filename, $offset );
$rc = $resp->sendfile( $filename, $offset, $len );
It returns a L<APR::Const> constant.
On success, L<APR::Const::SUCCESS> is returned.
In case of a failure, a failure code is returned, in which case normally it should be returned to the caller
=head2 server
Sets or gets the HTTP header field C<Server>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server>
=head2 server_timing
Sets or gets the HTTP header field C<Server-Timing>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>
=head2 set_content_length
Set the content length for this request, by calling L<Apache2::Response/set_content_length>
$resp->set_content_length( $length );
It does not return any value.
=head2 set_cookie
Sets or gets the HTTP header field C<Set-Cookie>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie>
=head2 set_etag
$resp->set_etag;
Set automatically the C<E-tag> outgoing header.
It does not return any value.
=head2 set_keepalive
$ret = $resp->set_keepalive;
Returns the keepalive status for this request, by calling L<Apache2::Response/set_keepalive>
It returns true if keepalive can be set, false otherwise.
=head2 set_last_modified
Sets the C<Last-Modified> response header field to the value of the mtime field in the request structure, rationalized to keep it from being in the future, by calling L<Apache2::Response/set_last_modified>
$resp->set_last_modified( $mtime );
If the C<$mtime> argument is passed, C<< $resp->update_mtime >> will be first run with that argument.
=head2 socket
my $socket = $resp->socket;
my $prev_socket = $resp->socket( $new_socket );
Get or set the client socket and returns a L<APR::Socket> object, by calling L<Apache2::Connection/client_socket>
=head2 sourcemap
Sets or gets the HTTP header field C<SourceMap>
See L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/SourceMap>
=head2 status
Get or set the reply status for the client request, by calling L<Apache2::RequestRec/status>
Normally you would use some L<Apache2::Const> constant, e.g. L<Apache2::Const::REDIRECT>.
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 ...
$resp->status( $some_code );
return( Apache2::Const::OK );
See also C<< $resp->status_line >>, which. if set, overrides C<< $resp->status >>.
=head2 status_line
my $status_line = $resp->status_line();
my $prev_status_line = $resp->status_line( $new_status_line );
Get or sets the response status line. The status line is a string like C<200 Document follows> and it will take precedence over the value specified using the C<< $resp->status() >> described above.
( run in 0.353 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )