libapa...uestRec(3pm)
β¨ NAME β¨
Apache2::RequestRec β the Perl API for Apache request record accessors. that's the whole thing. π
oh and if you're squinting at the header going "what is libapa...uestRec(3pm)" β that's literally this page, bestie, filed away under the User Contributed Perl Documentation. the name got truncated in the terminal header because terminals are haters. you found it, you're here, let's go. π«Ά
π Synopsis π
okay so here is literally every single thing this module can hand you, all in one delicious platter. no cap, just vibes and method calls:
use Apache2::RequestRec ();
# set supported by the handler HTTP methods
$allowed = $r->allowed();
# auth type
$auth_type = $r->ap_auth_type();
# QUERY_STRING
$args = $r->args();
# non-parsed-headers handler
$status = $r->assbackwards();
# how many bytes were sent
$bytes_sent = $r->bytes_sent();
# client connection record
$c = $r->connection();
# "Content-Encoding" HTTP response header
$r->content_encoding("gzip");
# the languages of the content
$languages = $r->content_languages();
# "Content-Encoding" HTTP response header
$r->content_type('text/plain');
# special response headers table
$err_headers_out = $r->err_headers_out();
# request mapped filename
$filename = $r->filename();
# request finfo
$finfo = $r->finfo();
# 'SetHandler perl-script' equivalent
$r->handler('perl-script');
# was it a HEAD request?
$status = $r->header_only();
# request input headers table
$headers_in = $r->headers_in();
# request output headers table
$headers_out = $r->headers_out();
# hostname
$hostname = $r->hostname();
# input filters stack
$input_filters = $r->input_filters();
# get the main request obj in a sub-request
$main_r = $r->main();
# what's the current request (GET/POST/etc)?
$method = $r->method();
# what's the current method number?
$methnum = $r->method_number();
# current resource last modified time
$mtime = $r->mtime();
# next request object (in redirect)
$next_r = $r->next();
# there is no local copy
$r->no_local_copy();
# Apache ascii notes table
$notes = $r->notes();
# output filters stack
$output_filters = $r->output_filters();
# PATH_INFO
$path_info = $r->path_info();
# used in configuration directives modules
$per_dir_config = $r->per_dir_config();
# pool with life span of the current request
$p = $r->pool();
# previous request object in the internal redirect
$prev_r = $r->prev();
# connection level input filters stack
$proto_input_filters = $r->proto_input_filters();
# HTTP protocol version number
$proto_num = $r->proto_num();
# connection level output filters stack
$proto_output_filters = $r->proto_output_filters();
# the protocol, the client speaks: "HTTP/1.0", "HTTP/1.1", etc.
$protocol = $r->protocol();
# is it a proxy request
$status = $r->proxyreq($val);
# Time when the request started
$request_time = $r->request_time();
# server object
$s = $r->server();
# response status
$status = $r->status();
# response status line
$status_line = $r->status_line();
# manipulate %ENV of the subprocess
$r->subprocess_env;
$r->subprocess_env($key => $val);
# first HTTP request header
$request = $r->the_request();
# the URI without any parsing performed
$unparsed_uri = $r->unparsed_uri();
# The path portion of the URI
$uri = $r->uri();
# auth username
$user = $r->user();
yes it's a lot. it's giving "one module to rule them all", and honestly? iconic. π
π Description π
Apache2::RequestRec is the Perl API for the Apache request_rec object. if a request is walking down the hallway, this is the girl holding the clipboard. main character energy, fr fr.
and she does not work alone. these packages all extend the Apache2::RequestRec functionality: Apache2::Access, Apache2::Log, Apache2::RequestIO, Apache2::RequestUtil, Apache2::Response, Apache2::SubRequest and Apache2::URI. squad goals, honestly. β¨
π₯ API π₯
Apache2::RequestRec provides the following functions and/or methods, bestie. strap in:
π allowed
get/set the allowed methods bitmask. it's a little bundle of bits that says which HTTP methods you'll even entertain. π
$allowed = $r->allowed();
$prev_allowed = $r->allowed($new_allowed);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_allowed( bitmask ) β sets the bitvector to a new value. - ret:
$allowed( bitmask ) β returns$allowed, which is a bitvector of the allowed methods.
if the $new_allowed argument is passed, then the value from before the change is what comes back at you.
- since:
2.0.00
okay so here's the important lore: a handler must make sure the request method is one it's actually capable of handling. generally, modules should Apache2::DECLINE any request methods they don't handle. but before you bail like that, you should set $r->allowed to the list of methods you're willing to deal with.
that bitvector is what gets used to build the Allow: header β you know, the one required for OPTIONS requests β plus the Apache2::Const::HTTP_METHOD_NOT_ALLOWED (405) and Apache2::Const::HTTP_NOT_IMPLEMENTED (501) status codes. so yeah, you need it. π
here's the tea: since the default Apache handler already deals with the OPTIONS method, basically all response handlers can just decline to deal with OPTIONS. like, say your response handler only handles GET and POST, and not OPTIONS? then you might wanna say:
use Apache2::Const -compile => qw(OK DECLINED M_GET M_POST M_OPTIONS);
if ($r->method_number == Apache2::Const::M_OPTIONS) {
$r->allowed($r->allowed | (1<<Apache2::Const::M_GET) | (1<<Apache2::Const::M_POST));
return Apache2::Const::DECLINED;
}
oh and p.s. β TRACE is always allowed, so modules don't need to set it explicitly. don't waste your energy, she already said yes. β¨
now for the messy part: since default_handler will always handle a GET, a module that does not implement GET should probably return Apache2::Const::HTTP_METHOD_NOT_ALLOWED. the catch? that means a script GET handler can't be installed by mod_actions. it's giving "the system is not your friend today". π
for example, if your module can handle only the POST method, it could start with:
use Apache2::Const -compile => qw(M_POST HTTP_METHOD_NOT_ALLOWED);
unless ($r->method_number == Apache2::Const::M_POST) {
$r->allowed($r->allowed | (1<<Apache2::Const::M_POST));
return Apache2::Const::HTTP_METHOD_NOT_ALLOWED;
}
π ap_auth_type
if an authentication check was made, get or set the ap_auth_type slot in the request record. cute little auth label, love that for her. π
$auth_type = $r->ap_auth_type();
$r->ap_auth_type($newval);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$newval(string) β if you pass this argument, a brand new auth type gets assigned. like so:
$r->auth_type('Basic');
- ret:
$auth_type(string) β if$newvalis passed, nothing comes back to you. otherwise, you get the current auth type. simple as that. - since:
2.0.00
so ap_auth_type holds the authentication type that's been negotiated between the client and the server during the actual request. the whole "we agreed on this, periodt" situation.
usually ap_auth_type gets populated automatically when you call $r->get_basic_auth_pw, so honestly you don't really need to stress about it too much. but if you wanna roll your own authentication mechanism? then yeah, you'll have to populate ap_auth_type yourself. you're on your own, bestie. π«Ά
fun throwback:$r->ap_auth_typewas$r->connection->auth_typeback in the mod_perl 1.0 API. glow-up confirmed. π
π args
get/set the request QUERY string. you know, the thing after the ?.
$args = $r->args();
$prev_args = $r->args($new_args);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_args( string ) β optionally set a whole new QUERY string. - ret:
$args( string ) β the current QUERY string.
if $new_args was passed, you get back the value from before the change instead.
- since:
2.0.00
π«£ assbackwards
when you set this to a true value, Apache won't send any HTTP response headers, which leaves the door wide open for you to send any headers yourself. bold move. π
$status = $r->assbackwards();
$prev_status = $r->assbackwards($newval);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$newval(integer) β assign a new state. - ret:
$status(integer) β the current state. - since:
2.0.00
β οΈ okay listen, this part matters: if you send your own set of headers, and that set includes theKeep-AliveHTTP response header, you must make sure to increment the number of requests served over this connection. normally the core connection output filterap_http_header_filterdoes that for you, but it gets skipped whenassbackwardsis enabled. so you gotta do it by hand:
$r->connection->keepalives($r->connection->keepalives + 1);
if you don't? code that relies on the value of $r->connection->keepalives may malfunction. for example, that counter is used to tell when a new request is coming in over the same connection to a filter that wants to parse only HTTP headers β like Apache2::Filter::HTTPHeadersFixup. so yeah, don't skip it. π
and of course, you'll need to set $r->connection->keepalive(1) as well.
π bytes_sent
the number of bytes sent to the client. super handy for logging and whatever else you're up to. π₯
$bytes_sent = $r->bytes_sent();
- obj:
$r(Apache2::RequestRec object) - ret:
$bytes_sent(integer) - since:
2.0.00
though, ngl, as of this writing in Apache 2.0 it doesn't really do what it did back in Apache 1.3. it's just set to the size of the response body. the issue is that buckets from one request may get buffered and not sent during the lifetime of the request, so it's not easy to give a truly accurate count of "bytes sent to the network for this response". it's giving "we tried". π
π connection
get the client connection record.
$c = $r->connection();
- obj:
$r(Apache2::RequestRec object) - ret:
$c(Apache2::Connection object) - since:
2.0.00
ποΈ content_encoding
get/set the content encoding (that's the Content-Encoding HTTP header). content encodings are strings like gzip or compress. β¨
$ce = $r->content_encoding();
$prev_ce = $r->content_encoding($new_ce);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_ce( string ) β if passed, sets the content encoding to a new value. it must be a lowercased string, no uppercase shenanigans allowed. - ret:
$ce( string ) β the current content encoding.
if $new_ce is passed, then the previous value comes back instead.
- since:
2.0.00
for example, here's how you send a gzip'ed response:
require Compress::Zlib;
$r->content_type("text/plain");
$r->content_encoding("gzip");
$r->print(Compress::Zlib::memGzip("some text to be gzipped));
π content_languages
get/set the content languages (that's the Content-Language HTTP header). content languages are strings like en or fr. multilingual queen. π
$languages = $r->content_languages();
$prev_lang = $r->content_languages($nev_lang);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_lang( ARRAY ref ) β if passed, sets the content languages to new values. it must be an ARRAY reference of language names, likeenorfr. - ret:
$languages( ARRAY ref ) β the current list of content languages, handed to you as an ARRAY reference.
if $new_lang is passed, then the previous value comes back instead.
- since:
2.0.00
π·οΈ content_type
get/set the HTTP response Content-type header value. the "what even is this file" label. π
my $content_type = $r->content_type();
my $prev_content_type = $r->content_type($new_content_type);
- obj:
$rβ anApache2::RequestRec objectπ - opt arg1:
$new_content_typeβ a MIME type string, aka your brand-new HTTP response content-type β¨ but bestie, it only affects the response if the HTTP headers haven't already been sent. Too late = no takebacks π - ret:
$content_typeβ the current content-type value. And if you passed$new_content_type, you get the previous value back instead, swapsies style π - since:
2.0.00
Like, say you wanna set the Content-type header to text/plain:
$r->content_type('text/plain');
β οΈ And if you set this header straight through the headers_out table? Apache literally ignores it. So do not do that, no cap.
π err_headers_out
Get/set MIME response headers β but these ones get printed even on errors AND they persist across internal redirects. Iconic behaviour tbh.
$err_headers_out = $r->err_headers_out();
- obj:
$r(Apache2::RequestRec object) - ret:
$err_headers_out(APR::Table object) - since:
2.0.00
So here's the tea between headers_out and err_headers_out: the err_headers_out ones get printed even on error, and they stick around across internal redirects β which means the headers printed for ErrorDocument handlers will totally have them π
Wanna see it in action? Say a handler wants to return a 404 but ALSO sneak in a cookie. It has to be:
$r->err_headers_out->add('Set-Cookie' => $cookie);
return Apache2::Const::NOT_FOUND;
But if the handler does this instead:
$r->headers_out->add('Set-Cookie' => $cookie);
return Apache2::Const::NOT_FOUND;
then the Set-Cookie header justβ¦ won't be sent. Gone. Ghosted π
πΈ filename
Get/set the filename on disk that corresponds to this response (aka the result of the URI β filename translation).
$filename = $r->filename();
$prev_filename = $r->filename($new_filename);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_filename(string) β the new value - ret:
$filename(string) β the current filename, or the previous value if you passed the optional$new_filenameargument - since:
2.0.00
π¨ Okay real talk: if you change the filename after thePerlMapToStorageHandlerphase ran, and you're expecting Apache to actually serve it, you need to update itsstatrecord too, like so:
use Apache2::RequestRec ();
use APR::Finfo ();
use APR::Const -compile => qw(FINFO_NORM);
$r->filename($newfile);
$r->finfo(APR::Finfo::stat($newfile, APR::Const::FINFO_NORM, $r->pool));
If you don't do that, Apache will keep trying to use the previously cached info about the old filename value. It's literally stuck in the past π
π¦ finfo
Get and set the finfo request record member:
$finfo = $r->finfo();
$r->finfo($finfo);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$finfo(APR::Finfo object) - ret:
$finfo(APR::Finfo object) β always returns the current object.
So here's the vibe: thanks to how Apache is implemented internally, you can't have two different objects coming from $r->finfo at the same time. Whenever $r->finfo gets updated, all the objects get updated too, to the latest value. Everyone's on the same page, always π«Ά
- since:
2.0.00
Most of the time you're using this method just to grab the finfo member. The only reason you might wanna set it is if you need it before Apache's default map_to_storage phase gets called.
Examples, bestie:
- What Apache thinks is the current request filename (post the
PerlMapToStorageHandlerphase):
use Apache2::RequestRec ();
use APR::Finfo ();
print $r->finfo->fname;
- Populate the
finfomember (normally, before thePerlMapToStorageHandlerphase):
use APR::Finfo ();
use APR::Const -compile => qw(FINFO_NORM);
my $finfo = APR::Finfo::stat(__FILE__, APR::Const::FINFO_NORM, $r->pool);
$r->finfo($finfo);
β¨ handler
Get/set the equivalent of the SetHandler directive.
$handler = $r->handler();
$prev_handler = $r->handler($new_handler);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_handler(string) β the new handler. - ret:
$handler(string) β the current handler. If$new_handleris passed, the previous value is returned instead. - since:
2.0.00
π
header_only
Did the client ask for headers only? Like, was the request method HEAD? π
$status = $r->header_only();
- obj:
$r(Apache2::RequestRec object) - ret:
$status(boolean) β returns true if the client is asking for headers only, false otherwise - since:
2.0.00
π headers_in
Get/set the request MIME headers:
$headers_in = $r->headers_in();
- obj:
$r(Apache2::RequestRec object) - ret:
$headers_in(APR::Table object) - since:
2.0.00
This table is available starting from the PerlHeaderParserHandler phase β so that's when you can slide in.
For example, you can use it to grab the cookie value the client sent ya, in the Cookie: header:
my $cookie = $r->headers_in->{Cookie} || '';
π headers_out
Get/set MIME response headers β and these get printed only on 2xx responses.
$headers_out = $r->headers_out();
- obj:
$r(Apache2::RequestRec object) - ret:
$headers_out(APR::Table object) - since:
2.0.00
See also err_headers_out, which lets you set headers for non-2xx responses AND persist them across internal redirects. That's the one for chaos moments π₯
β hostname
Host, as set by full URI or Host:
$hostname = $r->hostname();
$prev_hostname = $r->hostname($new_hostname);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_hostname(string) β the new value - ret:
$hostname(string) β the current hostname, or the previous value if you passed the optional$new_hostnameargument - since:
2.0.00
π§ input_filters
Get/set the first filter in a linked list of request-level input filters:
$input_filters = $r->input_filters();
$prev_input_filters = $r->input_filters($new_input_filters);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_input_filtersβ set a new value - ret:
$input_filters(Apache2::Filter object) β the first filter in the request-level input filters chain. If$new_input_filterswas passed, returns the previous value instead. - since:
2.0.00
Okay so for example, instead of using $r->read() to read the POST data, you could do an explicit walk through the incoming bucket brigades to grab that data yourself. The function read_post() below does exactly that β and honestly? It's literally what $r->read() does behind the scenes π
use APR::Brigade ();
use APR::Bucket ();
use Apache2::Filter ();
use Apache2::Const -compile => qw(MODE_READBYTES);
use APR::Const -compile => qw(SUCCESS BLOCK_READ);
use constant IOBUFSIZE => 8192;
sub read_post {
my $r = shift;
my $bb = APR::Brigade->new($r->pool,
$r->connection->bucket_alloc);
my $data = '';
my $seen_eos = 0;
do {
$r->input_filters->get_brigade($bb, Apache2::Const::MODE_READBYTES,
APR::Const::BLOCK_READ, IOBUFSIZE);
for (my $b = $bb->first; $b; $b = $bb->next($b)) {
if ($b->is_eos) {
$seen_eos++;
last;
}
if ($b->read(my $buf)) {
$data .= $buf;
}
$b->remove; # optimization to reuse memory
}
} while (!$seen_eos);
$bb->destroy;
return $data;
}
So yeah, like you can see, $r->input_filters hands us a pointer to the last of the top of the incoming filters stack. Main character pointer energy, fr fr π
π main
Get the main request record:
$main_r = $r->main();
- obj:
$r(Apache2::RequestRec object) - ret:
$main_r(Apache2::RequestRec object) β if the current request is a sub-request, this method returns a blessed reference to the main request structure. But if the current request is the main request, then this method returnsundef.
Wanna figure out whether you're inside a main request or a sub-request/internal redirect? Use $r->is_initial_req.
- since:
2.0.00
πΈ method
Get/set the current request method (e.g. GET, HEAD, POST, etc.):
$method = $r->method();
$pre_method = $r->method($new_method);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_method(string) β a new value - ret:
$method(string) β the current method as a string. If$new_methodwas passed, the previous value is returned instead. - since:
2.0.00
π¦ method_number
Get/set the HTTP method issued by the client (Apache2::Const::M_GET, Apache2::Const::M_POST, etc.)
$methnum = $r->method_number();
$prev_methnum = $r->method_number($new_methnum);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_methnum(Apache2::Const :methods constant) β a new value - ret:
$methnum(Apache2::Const :methods constant) β the current method as a number. If$new_methnumwas passed, the previous value is returned instead. - since:
2.0.00
Wanna see it used? Peep the $r->allowed entry for examples π
β mtime
Last modified time of the requested resource:
$mtime = $r->mtime();
$prev_mtime = $r->mtime($new_mtime);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_mtime(epoch seconds). β a new value - ret:
$mtime(epoch seconds). β the current value. If$new_mtimewas passed, the previous value is returned instead. - since:
2.0.00
π next
Pointer to the redirected request if this is an external redirect.
$next_r = $r->next();
- obj:
$r(Apache2::RequestRec object) - ret:
$next_r(Apache2::RequestRec object) β returns a blessed reference to the next (internal) request structure, orundefif there's no next request. - since:
2.0.00
π no_local_copy
There is no local copy of this response.
$status = $r->no_local_copy();
- obj:
$r(Apache2::RequestRec object) - ret:
$status(integer) - since:
2.0.00
This one gets used internally in certain sub-requests to stop Apache2::Const::HTTP_NOT_MODIFIED from being sent for a fragment or error documents. For example, go look at the implementation in modules/filters/mod_include.c.
It's also used internally in $r->meets_conditions β and if it's set to a true value, the conditions are always met. Automatic win π
π notes
Get/set text notes for the duration of this request. These notes can travel from one module to another (and it's not just mod_perl β modules in any other language too):
$notes = $r->notes();
$prev_notes = $r->notes($new_notes);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_notes(APR::Table object) - ret:
$notes(APR::Table object) β the current notes table. If the$new_notesargument was passed, returns the previous value instead. - since:
2.0.00
π«Ά Pro tip bestie: if you wanna pass Perl structures around, use $r->pnotes instead.
Also see $c->notes
β¨ output_filters β¨
Grab the very first filter in the linked list of request-level output filters, bestie:
$output_filters = $r->output_filters();
$prev_output_filters = $r->output_filters($new_output_filters);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_output_filtersβ sets a new value, if you feel like it π - ret:
$output_filters(Apache2::Filter object) β the first filter in the request-level output filters chain. And if you passed$new_output_filters, you get the previous value back, no cap. - since: 2.0.00
So like, instead of using $r->print() to yeet the response body out, you can send the data straight to the first output filter. The function send_response_body() below does exactly that:
use APR::Brigade ();
use APR::Bucket ();
use Apache2::Filter ();
sub send_response_body {
my ($r, $data) = @_;
my $bb = APR::Brigade->new($r->pool,
$r->connection->bucket_alloc);
my $b = APR::Bucket->new($bb->bucket_alloc, $data);
$bb->insert_tail($b);
$r->output_filters->fflush($bb);
$bb->destroy;
}
And fr fr, that's literally what $r->read() does behind the scenes πΈ β except it also knows how to parse HTTP headers that got passed along with the data, and it implements buffering too, which the function above lowkey does not. So like, don't come for it.
β¨ path_info β¨
Get or set the PATH_INFO β that's whatever's left in the path after the URI β filename translation happens:
$path_info = $r->path_info();
$prev_path_info = $r->path_info($path_info);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$path_info( string ) β set a new value - ret:
$path_info( string ) β returns the current value. If the optional arg$path_infois passed, you get the previous value instead. - since: 2.0.00
β¨ per_dir_config β¨
Get the dir config vector π:
$per_dir_config = $r->per_dir_config();
- obj:
$r(Apache2::RequestRec object) - ret:
$per_dir_config(Apache2::ConfVector object) - since: 2.0.00
For an indepth discussion, go check out the Apache Server Configuration Customization in Perl chapter. It's giving required reading, ngl.
β¨ pool β¨
The pool that's associated with the request:
$p = $r->pool();
- obj:
$r(Apache2::RequestRec object) - ret:
$p(APR::Pool object) - since: 2.0.00
β¨ prev β¨
Pointer to the previous request β but only if this is an internal redirect π:
$prev_r = $r->prev();
- obj:
$r(Apache2::RequestRec object) - ret:
$prev_r(Apache2::RequestRec object) β a blessed reference to the previous (internal) request structure, orundefif there's no previous request. Sad. Empty. Void. π - since: 2.0.00
β¨ proto_input_filters β¨
Get the first filter in a linked list of protocol-level input filters:
$proto_input_filters = $r->proto_input_filters();
$prev_proto_input_filters = $r->proto_input_filters($new_proto_input_filters);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_proto_input_filtersβ set a new value - ret:
$proto_input_filters(Apache2::Filter object) β the first filter in the protocol-level input filters chain. If$new_proto_input_filterswas passed, returns the previous value instead. - since: 2.0.00
And fun fact bestie: $r->proto_input_filters points to the same filter as $r->connection->input_filters. They're twinsies π«Ά
β¨ proto_num β¨
Get the current request's HTTP protocol version number, as a lil number:
$proto_num = $r->proto_num();
- obj:
$r(Apache2::RequestRec object) - ret:
$proto_num(integer) β current request's HTTP protocol version number, e.g.: HTTP/1.0 == 1000, HTTP/1.1 = 1001 - since: 2.0.00
β¨ proto_output_filters β¨
Get the first filter in a linked list of protocol-level output filters:
$proto_output_filters = $r->proto_output_filters();
$prev_proto_output_filters = $r->proto_output_filters($new_proto_output_filters);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_proto_output_filtersβ set a new value - ret:
$proto_output_filters(Apache2::Filter object) β the first filter in the protocol-level output filters chain. If$new_proto_output_filterswas passed, returns the previous value instead. - since: 2.0.00
And again, iconic detail: $r->proto_output_filters points to the same filter as $r->connection->output_filters. Matchies β¨
β¨ protocol β¨
Get a string that identifies the protocol the client speaks π£οΈ:
$protocol = $r->protocol();
- obj:
$r(Apache2::RequestRec object) - ret:
$protocl( string ) β typical values areHTTP/1.0orHTTP/1.1. And if the client didn't bother to specify the protocol version, the default isHTTP/0.9β retro of them π - since: 2.0.00
β¨ proxyreq β¨
Get/set the proxyrec request record member, and optionally adjust other related fields while you're at it:
$status = $r->proxyreq($val);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$val( integer ) βPROXYREQ_NONE,PROXYREQ_PROXY,PROXYREQ_REVERSE,PROXYREQ_RESPONSE - ret:
$status( integer ) β if$valis defined, the proxyrec member gets set to that value and the previous value comes back to you. If$valis not passed, and$r->proxyreqisn't true, and the proxy request is matching the current vhost (scheme, hostname and port), then the proxyrec member gets set toPROXYREQ_PROXYand that value is returned. On top of that,$r->uriis set to$r->unparsed_uriand$r->filenameis set to"modperl-proxy:".$r->uri. And if those conditions aren't true? You get0π - since: 2.0.00
So say you wanna turn a normal request into a proxy request to be handled on the same server in the PerlTransHandler phase β run this:
my $real_url = $r->unparsed_uri;
$r->proxyreq(Apache2::Const::PROXYREQ_PROXY);
$r->uri($real_url);
$r->filename("proxy:$real_url");
$r->handler('proxy-server');
Okay but listen, important: if you want to turn a proxy request into a non-proxy request, it is NOT enough to just call:$r->proxyreq(Apache2::Const::PROXYREQ_NONE);You also need to adjust$r->uriand$r->filenameif you're running that code in thePerlPostReadRequestHandlerphase β because if you don't,mod_proxy's own post_read_request handler will straight up override your settings (since it runs after the mod_perl handler). Not me getting my config stomped on π
And you may also wanna add:
$r->set_handlers(PerlResponseHandler => []);
so that any response handlers matching apache directives won't run in addition to the mod_proxy content handler. Two handlers fighting = chaos, and not the cute kind.
β¨ request_time β¨
The time when the request started β°:
$request_time = $r->request_time();
- obj:
$r(Apache2::RequestRec object) - ret:
$request_time(epoch seconds). - since: 2.0.00
β¨ server β¨
Get the Apache2::Server object for the server that request $r is running under:
$s = $r->server();
- obj:
$r(Apache2::RequestRec object) - ret:
$s(Apache2::ServerRec object) - since: 2.0.00
β¨ status β¨
Get/set the reply status for the client request π:
$status = $r->status();
$prev_status = $r->status($new_status);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_status( integer ) β if$new_statusis passed, the new status gets assigned. Normally you'd use someApache2::Const constant, e.g.Apache2::Const::REDIRECT. - ret:
$newval( integer ) β the current value. If$new_statusis passed, the old value is returned. - since: 2.0.00
Usually you set this value indirectly by returning the status code as the handler's function result. But sometimes β rare instances, bestie β you wanna trick Apache into thinking your module returned an Apache2::Const::OK status code while you actually send the browser a non-OK status. Sneaky. This is super handy when you're implementing an HTTP proxy handler, because the proxy handler needs to send the client whatever status code the proxied server returned, while returning Apache2::Const::OK to Apache. Like so:
$r->status($some_code);
return Apache2::Const::OK
Also peep $r->status_line, which β if you set it β overrides $r->status. The way that it just takes over π
β¨ status_line β¨
Get/set the response status line. The status line is a string like 200 Document follows, and it will take precedence over the value you specified using the $r->status() described above. Queen behavior honestly:
$status_line = $r->status_line();
$prev_status_line = $r->status_line($new_status_line);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_status_line( string ) - ret:
$status_line( string ) - since: 2.0.00
So when we were talking about $r->status earlier, we mentioned that sometimes a handler runs to a successful completion but still needs to return a different code β which is exactly the proxy server situation. Assuming the proxy handler forwards whatever response the proxied server sent to the client, it'll usually use status_line(), like this:
$r->status_line($response->code() . ' ' . $response->message());
return Apache2::Const::OK;
In this example $response could be, for example, an HTTP::Response object, if LWP::UserAgent was used to implement the proxy. iykyk π
This method is also lowkey iconic when you extend the HTTP protocol and add new response codes. Like, you could literally invent a brand-new error code and tell Apache to use it in the response like so:
$r->status_line("499 We have been FooBared");
return Apache2::Const::OK;
Here 499 is the new response code, and We have been FooBared is the custom response message. We made that up and Apache said "okay bet" π₯
β¨ subprocess_env β¨
Get/set the Apache subprocess_env table, or optionally set the value of a single named entry:
$r->subprocess_env;
$env_table = $r->subprocess_env;
$r->subprocess_env($key => $val);
$val = $r->subprocess_env($key);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$key( string ) - opt arg2:
$val( string ) - ret:
"..." - since: 2.0.00
Okay so here's the breakdown bestie:
When it's called in VOID context with no arguments, it populates %ENV with special variables (e.g. $ENV{QUERY_STRING}) just like mod_cgi does π§
When it's called in a non-VOID context with no arguments, it returns an APR::Table object.
When the $key argument (string) is passed, it returns the corresponding value (if such a thing exists, otherwise undef). These two lines are literally equivalent:
$val = $r->subprocess_env($key);
$val = $r->subprocess_env->get($key);
When the $key and the $val arguments (strings) are both passed, the value gets set. These two lines are equivalent too:
$r->subprocess_env($key => $val);
$r->subprocess_env->set($key => $val);
The subprocess_env "table" is used by Apache2::SubProcess to pass environment variables to externally spawned processes. It's also used by various Apache modules, and you should use this table to pass the environment variables, periodt. So for example, if in PerlHeaderParserHandler you do:
$r->subprocess_env(MyLanguage => "de");
you can then deploy mod_include and write in .shtml document:
<!--#if expr="$MyLanguage = en" -->
English
<!--#elif expr="$MyLanguage = de" -->
Deutsch
<!--#else -->
Sorry
<!--#endif -->
okay bestie, first thing in this chunk is that lil multilingual template snippet up there βοΈ β it's literally what's sitting at the top of the page, so we're keeping it verbatim, no cap. everything stays π
the_request
First HTTP request header π«Ά
$request = $r->the_request();
$old_request = $r->uri($new_request);
yes that second line really does say $r->uri in the source β we're copying it character-for-character, don't come for me π
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_request( string ) - ret:
$request( string )
for example:
GET /foo/bar/my_path_info?args=3 HTTP/1.0
- since:
2.0.00
unparsed_uri
The URI without any parsing performed β like, the raw untouched version, zero glow-up, zero edits β¨
$unparsed_uri = $r->unparsed_uri();
- obj:
$r(Apache2::RequestRec object) - ret:
$unparsed_uri( string ) - since:
2.0.00
so if the request was, say:
GET /foo/bar/my_path_info?args=3 HTTP/1.0
then $r->uri hands you back:
/foo/bar/my_path_info
whereas $r->unparsed_uri hands you back:
/foo/bar/my_path_info?args=3
see the difference? one is the path, the other is the whole little outfit π₯
uri
The path portion of the URI π¦
$uri = $r->uri();
my $prec_uri = $r->uri($new_uri);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_uri( string ) - ret:
$uri( string ) - since:
2.0.00
peep the example in the $r->unparsed_uri section right above β¬οΈ it's giving same energy.
user
Get the user name, if an authentication process was successful. Or set it. π
$user = $r->user();
$prev_user = $r->user($new_user);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$new_user( string ) β pass$new_userto set a new value - ret:
$user( string ) β the current username if an authentication process was successful. If$new_userwas passed, the previous value is returned. - since:
2.0.00
for example, let's print the username passed by the client:
my ($res, $sent_pw) = $r->get_basic_auth_pw;
return $res if $res != Apache2::Const::OK;
print "User: ", $r->user;
π Unsupported API π
so Apache2::RequestRec also provides an auto-generated Perl interface for a few other methods, and those ones? not tested at the moment, which means their API is a subject to change. they'll be finalized later as a need arises. so if you want to rely on any of the methods down here, pls contact the mod_perl development mailing list so we can help each other take the steps necessary to shift the method to an officially supported API π«Ά teamwork makes the dream work fr fr
allowed_methods
META: Autogenerated - needs to be reviewed/completed
List of allowed methods
$list = $r->allowed_methods();
- obj:
$r(Apache2::RequestRec object) - ret:
$list(Apache2::MethodList object) - since:
2.0.00
META: Apache2::MethodList is not available at the moment π
allowed_xmethods
META: Autogenerated - needs to be reviewed/completed
Array of extension methods
$array = $r->allowed_xmethods();
- obj:
$r(Apache2::RequestRec object) - ret:
$array(APR::ArrayHeader object) - since:
2.0.00
META: APR::ArrayHeader is not available at the moment π
request_config
Config vector containing pointers to request's per-server config structures β
$ret = $r->request_config($newval);
- obj:
$r(Apache2::RequestRec object) - opt arg1:
$newval(Apache2::ConfVector object) - since:
2.0.00
used_path_info
META: Autogenerated - needs to be reviewed/completed
Flag for the handler to accept or reject path_info on the current request. All modules should respect the AP_REQ_ACCEPT_PATH_INFO and AP_REQ_REJECT_PATH_INFO values, while AP_REQ_DEFAULT_PATH_INFO indicates they may follow existing conventions. This is set to the user's preference upon HOOK_VERY_FIRST of the fixups. πΈ
$ret = $r->used_path_info($newval);
- obj:
$r(Apache2::RequestRec object) - arg1:
$newval(integer) β heads up bestie, this one's a plainarg1, not an optional one π - since:
2.0.00
π See Also π
mod_perl 2.0 documentation. that's the whole vibe, go read it π
π Copyright π
mod_perl 2.0 and its core modules are copyrighted under The Apache Software License, Version 2.0.
π Authors π
The mod_perl development team and numerous contributors.
and that's the whole page, periodt π this lil icon is libapa...uestRec(3pm), pulled from perl v5.42.3, dated 2026-08-20 β ate and left no crumbs πβ¨ go write some bomb Perl, bestie π«Ά
π¦ where this page comes from
- ubuntu stonking: libapache2-mod-perl2 2.0.13-2build3 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms