Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Perl Web Development - From Novice To Professional (2006)

.pdf
Скачиваний:
57
Добавлен:
17.08.2013
Размер:
2.9 Mб
Скачать

220 C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

Figure 11-14. Printing the user agent based on output from the headers_in() method

Accessing the Response

Using the Apache request object, you can set headers in the response, as well as to send server status codes.

Setting a Response Header

Earlier, you saw an example to send the Content-Type response header. As a refresher, that code looks like this:

my $r = shift; $r->send_http_header('text/html');

The method used, send_http_header(), is fine for the examples that were shown insofar as it sets the Content-Type and sends the header on its way. However, if you need to set other headers in the response, then calling send_http_header will preclude that from happening. Rather, if you need to set the Content-Type and set other headers in the response, you should use the content_type() method, and then use the send_http_header() method, as in this example:

my $r = shift $r->content_type('text/html'); $r->send_http_header();

By using the content_type() method and send_http_header() methods separately in this way, you can set other headers prior to sending them to the client. You can set other headers within the response using the methods described in Table 11-1.

C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

221

Table 11-1. Methods for Response Headers

Method

Description

content_type()

Sets the MIME type as will be sent by the Content-Type header

set_content_length()

Sets the Content-Length header

set_last_modified()

Sets the Last-Modified header

no_cache()

Sets the No_Cache header

 

 

To set nonstandard headers, you can use another method, header_out(), as in this example:

my $r = shift;

$r->header_out("X-Server" => "My Apache Server v4"); $r->send_http_header;

Setting Response Status

Response codes are likely familiar to any web user. From a 404 Not Found to a 500 Internal Server Error or a 200 OK, these response codes communicate the status of the response back to the requesting client. The Apache::Constants class makes these response codes available to you. The response codes available through Apache::Constants use a relatively friendly name. Some of the more common names are described in Table 11-2.

Table 11-2. Apache::Constants for Server Status Messages

Apache::Constants Name

Status Code

REDIRECT

302 Found

NOT_FOUND

404 Not Found

SERVER_ERROR

500 Internal Server Error

OK

200 OK

AUTH_REQUIRED

401 Unauthorized

 

 

This code sends a 404 Not Found error to the client:

use Apache::Constants qw/:common/;

my $r = shift;

$r->status(NOT_FOUND);

This is a simple example. Of interest here is that the Apache::Constants class is loaded into the namespace. Notice that only the common set of status codes were imported into the namespace. Rarely will a program call for status codes from Apache::Constants that are not within the common namespace. You can also import only the status codes that you need for a given task. For example, in the previous example, it would be better to just import NOT_FOUND into the program’s namespace, as shown here:

222C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

use Apache::Constants (NOT_FOUND);

my $r = shift;

$r->status(NOT_FOUND);

Note You can also use methods for specific error headers. See the documentation for Apache::Table and mod_perl for more information about these headers.

Working with Cookies

As you know, cookies are another object that can be sent in the HTTP header. You can use the Apache::Cookie class, part of libapreq, to set and retrieve cookies the mod_perl way.

Jump in the wayback machine to Chapter 1, which covered cookies in detail. There, you learned all about the values for cookies and how to set them with CGI.pm. Unlike CGI.pm, Apache::Cookie is written in C. This section looks at writing and reading cookies using Apache::Cookie.

Writing Cookies

Cookies are written or sent to the client by instantiating a new Apache::Cookie object. The Apache::Cookie class contains methods that correspond to the various elements of a cookie, such as name, value, path, secure, expires, and so on. You can set these values when instantiating the object through the new() method or via calls to their respective method. Table 11-3 lists the methods, as well as the name of the corresponding parameter if you’re using them when instantiating the object.

Table 11-3. Apache::Cookie Methods and Parameters

Method

Parameter

Description

name()

-name

The cookie name

value()

-value

The cookie’s value

expires()

-expires

The cookie’s expiration

domain()

-domain

The domain from which the cookie can be read

path()

-path

The path for the cookie

secure()

-secure

Whether or not the cookie must be read over an SSL transport

 

 

 

The cookies are sent to the browser with the bake() method. Listing 11-11 (Cookiewriter.cgi) shows an example that sets a cookie called testcookie using the Apache::Cookie class.

C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

223

Listing 11-11. Sending a Cookie with Apache::Cookie

use Apache::Cookie;

use strict;

my $r = shift;

my $cookie = Apache::Cookie->new($r, -name => "testcookie", -value => "testvalue", -path => "/",

);

$cookie->bake();

$r->send_http_header();

The values for the cookie in the example are set via the new() method, and the bake() method is called to actually send the cookie to the client. The cookie arriving at the browser is shown in Figure 11-15.

Figure 11-15. The cookie set with Apache::Cookie

You can also set or change the parameter values for cookies by calling each individual method prior to calling bake(). For example, the program in Listing 11-12 (Securecookie.cgi) sets the secure flag on the cookie after it has already been instantiated with the new() method.

Listing 11-12. Sending a Secure Cookie

use Apache::Cookie;

use strict;

my $r = shift;

224C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

my $cookie = Apache::Cookie->new($r, -name => "securecookie", -value => "securevalue", -path => "/",

);

$cookie->secure('1');

$cookie->bake();

$r->send_http_header();

Notice that, in addition to the purely superficial name of the cookie itself changing, the secure method() is also called in this code:

$cookie->secure('1');

When sent to the browser, this will mean that the cookie can be read only over an encrypted channel such as over SSL. The cookie alert dialog box is shown in Figure 11-16. Notice the “Send For: Encrypted connections only” wording in this cookie.

Figure 11-16. A dialog box indicating that a cookie with the secure flag was sent

Reading Cookies

You can also use Apache::Cookie to read cookies that are sent by the client. You can use either the parse() method or the fetch() method to retrieve the cookies.

The parse() method operates in three modes: the method can retrieve all cookies as a hash reference, as a hash, or individually. Listing 11-13 (Cookiereader.cgi) shows an example of retrieving cookies using Apache::Cookie’s parse() method as a hash.

Listing 11-13. Retrieving a Cookie with Apache::Cookie

use Apache::Cookie;

use strict;

my $r = shift;

C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

225

my %cookies = Apache::Cookie->new($r)->parse;

$r->send_http_header('text/plain');

foreach my $cookie (keys %cookies) {

print "Name: ", $cookies{$cookie}->name, "\n"; print "Value: ", $cookies{$cookie}->value, "\n";

}

The results of this code, when called through a browser, are shown in Figure 11-17.

Figure 11-17. Retrieving cookies using Apache::Cookie and printing the names and values of the cookies

Note Make sure you actually set a cookie before trying to retrieve the cookie with the code in Listing 11-13. It only took me about ten minutes to figure out that I hadn’t set a cookie, which is why my code wasn’t producing any output.

Uploading Files

Uploading files is another area where there is also a suitable CGI.pm function for accomplishing the task. However, using Apache::Request and Apache::Upload can yield better performance.

The main interface for uploading files with Apache::Upload is the upload() method. This method can be called in a scalar context, and it will return a single upload object. If called in

226C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

a list context, the upload() method will return objects corresponding to the number of files uploaded.

Apache::Upload contains a number of methods for working with uploaded files. For more information about working with file uploads through Apache::Upload, see the Perl documentation for Apache::Upload.

Working with the Apache Server

Like the HTTP request, the behavior of the Apache server itself can be examined and controlled using mod_perl. The Apache::Server object enables things like child creation and log control through a mod_perl interface. This section looks at the Apache::Server object.

Using Apache::Server is similar to Apache::Request in that you’ll typically create an instance of the server local to your program, with something like this:

my $r = shift;

my $server = $r->server;

More commonly, you’ll see the Apache server object placed into a variable called $s, like this:

my $s = $r->server;

The server object in this example is created from the current request object; you can see that the $r request object is created first. This means that the server object will be related to whatever server section is actually serving the request within the Apache configuration. You could also call Apache::Server directly, which would then give you an object related to the properties that aren’t specific to the current request.

Caution Any changes made to the Apache server through the Apache server object will last for the lifetime of the child Apache process.

Getting Information About the Server

Through the Apache server object, you can find out a lot about the Apache server itself, all from within a Perl program. As an example, Listing 11-14 (Showserver.cgi) prints out some information about the server using various methods available with Apache::Server.

Listing 11-14. Printing Information About the Apache Server

use strict;

my $r = shift;

my $s = $r->server;

$r->send_http_header('text/plain');

C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

227

print "UID: ", $s->uid, "\n"; print "GID: ", $s->gid, "\n"; print "Port: ", $s->port, "\n";

print "Timeout: ", $s->timeout, "\n"; print "ErrorLog: ", $s->error_fname, "\n";

print "ServerName: ", $s->server_hostname, "\n";

When viewed through a browser, the output looks similar to that in Figure 11-18.

Figure 11-18. Output from a program to get information about the server

Note Here’s some trivia: The server name in Figure 11-18, ord, is named after the O’Hare Airport in Chicago.

For more information about the methods available with Apache::Server, see the Perl documentation for Apache::Server.

Controlling Logging

Another interface to work with the Apache server is through Apache::Log. Using Apache::Log, you can write to the Apache error log.

Within the error log are eight levels of errors, corresponding to the logging levels available on a Linux system, such as warn, info, debug, error, and so on. Each of these logging levels has its own method within Apache::Log. In other words, by calling the individual method, you can control which logging level will be used. The logging level methods are as follows:

228C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

emerg()

alert()

crit()

error()

warn()

notice()

info()

debug()

A log object is instantiated through a current request within a mod_perl program:

my $log = $r->server->log;

There’s really not much to writing a log entry. Instantiate a request object, then instantiate a log object, and then write to the log. Listing 11-15 (Logger.cgi) shows an example.

Listing 11-15. Printing to the Error Log with Apache::Log

use Apache::Log;

use strict;

my $r = shift;

my $log = $r->server->log;

$log->error("Moo");

When executed, this code produces an entry in the error log like this:

[Sat Jun 11 20:12:23 2005] [error] Moo

As previously stated, Apache::Log can write at any of the eight logging levels, so instead of calling the error() method, you could make that a warning instead:

use Apache::Log;

use strict;

my $r = shift;

my $log = $r->server->log;

$log->warn("Moo");

C H A P T E R 1 1 D E V E L O P M E N T W I T H M O D _ P E R L

229

This would produced a warning in the error log:

[Sat Jun 11 20:14:32 2005] [warn] Moo

Note If you’re not receiving an error message in your log file, check the LogLevel directive in your Apache configuration.

Listing 11-16 (Logua.cgi) shows another example that incorporates a log message with an earlier example to look at the user agent. This code will print a warning in the error log if the site is visited by an Internet Explorer user.

Listing 11-16. Logging Based on the User Agent

use Apache::Log;

use strict;

my $r = shift;

my $log = $r->server->log;

$r->send_http_header('text/plain');

my %headers = $r->headers_in();

if ($headers{'User-Agent'} =~ m/MSIE/) { $log->warn("Someone is actually still using IE");

}

When visited by a browser with the string MSIE in UserAgent, the warning is printed in the error log:

[Sat Jun 11 20:22:16 2005] [warn] Someone is actually still using IE

Security Considerations with mod_perl, Revisited

As noted in Chapter 10, using mod_perl introduces its own set of security risks. Since the Perl interpreter is embedded into the Apache process, and since namespaces can be shared, there is potential for data to be read and possibly altered within and between programs running with mod_perl. Keeping namespaces clean by using local variable scope and using the use strict pragma go a long way toward mitigating this risk. This is less of a concern on a server that isn’t shared.