- Introduction
- The Apache Request Object
- The HTTP Request Message
- The Client Request
- Accessing Client Request Headers
- Accessing HTML Form Fields
- Reading POSTed Data Manually
- Manipulating Cookies
- Handling File Uploads
- Setting Server Response Headers
- Controlling Caching Behavior
- Sending Server Response Headers
- Setting the Response Status
- Setting Error Headers
- Manipulating Headers with Multiple Like Fields
- Using Subrequests
- Setting Headers for Subrequests
- Short-Circuiting Subrequests
- Getting or Setting the Request Method
- Accessing the Request Object from XS
Manipulating Headers with Multiple Like Fields
You want to manipulate headers that have multiple like header fields, but assigning them to a hash removes all but the last value.
Technique
Use the Apache::Table class to access your headers.
# Take a peek at what we are going to set. my @cookies = $r->headers_out->get('Set-Cookie');
Comments
Calling headers_in() or headers_out() and assigning the return value to a hash has its limitations, especially when dealing with headers that may have more than one entry in the table, such as Set-Cookie. As we have mentioned a few times, calling either of these methods in a scalar context returns an Apache::Table object, which has its own set of methods in particular, the get() method, which returns a single value in a scalar context or a list of values in a list context.
Actually, the Apache::Table class is an important one to be familiar with, in part because it is the underlying class for many methods, including methods for manipulating some fields of the Apache request record:
- err_headers_out()
- headers_in()
- headers_out()
- notes()
- subprocess_env()
as well as these additional methods:
- dir_config() from the Apache class
- info() from the Apache::Upload class
- param() from the Apache::Request class
The Apache::Table class offers a consistent, powerful interface for manipulating the data beneath each of these methods. It ties into Apache's internal table structure, which allows for things such as headers to be stored in a case-insensitive manner with multiple values per key. This comes in handy when joining the case-insensitive HTTP protocol with case-sensitive Perl, making calls such as
my $encodings = $r->headers_in->get('accept-encoding');
successful, no matter how the user agent capitalized the header.
Apache::Table has only a handful of methods:
- add()
- clear()
- do()
- get()
- merge()
- new()
- set()
- unset()
of which you will probably only use a few in everyday programming. Although most should be self-explanatory, do() is a unique method that allows you to iterate over the entire table and uses a special idiom.
# Most user agents string multiple cookies together # using ";" as the separator. Break these cases apart # so each appears as a separate entry. $r->headers_in->do(sub { # The key/value pair is passed as the argument list. my ($key, $value) = @_; if ($key =~ m/Cookie/) { print map { "Cookie => $_\n" } split /;\s?/, $value; } else { print " $key => $value\n"; } # do() exits on false, so we add this as good programming practice. 1; });
Using the various Apache::Table methods to access mod_perl data structures has many advantages. As we demonstrated in Recipe 2.14, the PerlAddVar construct is made possible through the use of the Apache::Table framework and the $r->dir_config->get() interface, which allows programmers to access an entire array of values set within a configuration. Aside from typical uses like this, it pays to take a moment and contemplate the full range of power that you have available through the Apache::Table methods. For instance, although setting an outgoing header using the following might seem perfectly intuitive:
$r->headers_out->set('Set-Cookie' => 'punishment=plank');
you can also do things like
# Add values to our configuration. $r->dir_config->set(Filter => 'On');
which is equivalent to setting
PerlSetVar Filter On
in your httpd.conf for use by later handlers in the request. Cool.