Presentation is loading. Please wait.

Presentation is loading. Please wait.

Transitioning to mod_perl Handlers

Similar presentations


Presentation on theme: "Transitioning to mod_perl Handlers"— Presentation transcript:

1 Transitioning to mod_perl Handlers
Geoffrey Young

2 Overview

3 Overview Apache and mod_perl 101

4 Overview Apache and mod_perl 101 mod_perl Handler Basics

5 Overview Apache and mod_perl 101 mod_perl Handler Basics
mod_perl Handler API Basics

6 Overview Apache and mod_perl 101 mod_perl Handler Basics
mod_perl Handler API Basics Using the Apache Framework

7 Overview Apache and mod_perl 101 mod_perl Handler Basics
mod_perl Handler API Basics Using the Apache Framework Advanced mod_perl API Features

8 Overview Apache and mod_perl 101 mod_perl Handler Basics
mod_perl Handler API Basics Using the Apache Framework Advanced mod_perl API Features Transition Strategies

9

10 Apache's Pre-fork Model

11 Apache's Pre-fork Model
Apache parent process

12 Apache's Pre-fork Model
Apache parent process httpd (parent)

13 Apache's Pre-fork Model
Apache parent process forks multiple child processes httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child)

14 Roles and Responsibilities

15 Roles and Responsibilities
httpd parent processes no actual requests

16 Roles and Responsibilities
httpd parent processes no actual requests all requests are served by the child processes

17 Roles and Responsibilities
httpd parent processes no actual requests all requests are served by the child processes requests are handled by any available child process, not necessarily the one that handled the previous request

18 Roles and Responsibilities
httpd parent processes no actual requests all requests are served by the child processes requests are handled by any available child process, not necessarily the one that handled the previous request remember, the HTTP is stateless by default

19 Children are Individuals
httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child)

20 Children are Individuals
httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child)

21 Children are Individuals
httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child)

22 Nice, Responsible Children

23 Nice, Responsible Children
each httpd child processes one incoming request at a time

24 Nice, Responsible Children
each httpd child processes one incoming request at a time only when the request is over is the child free to serve the next request

25 Nice, Responsible Children
each httpd child processes one incoming request at a time only when the request is over is the child free to serve the next request over time httpd child processes are terminated and replaced with fresh children

26 Request Phases

27 Request Phases Apache breaks down request processing into separate, logical parts called phases

28 Request Phases Apache breaks down request processing into separate, logical parts called phases client request logging URI-based init content URI translation fixups file-based init MIME setting resource control

29 Request Phases Apache breaks down request processing into separate, logical parts called phases each request is stepped through the phases until...

30 Request Phases Apache breaks down request processing into separate, logical parts called phases each request is stepped through the phases until... all processing is complete

31 Request Phases Apache breaks down request processing into separate, logical parts called phases each request is stepped through the phases until... all processing is complete somebody throws an "error"

32 Request Phases Apache breaks down request processing into separate, logical parts called phases each request is stepped through the phases until... all processing is complete somebody throws an "error" developers are given the chance to hook into each phase to add custom processing

33 Apache Request Cycle client request

34 Apache Request Cycle client request GET /perl-status HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Cache-Control: no-cache Connection: Keep-Alive, TE Host: User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera [en]

35 Apache Request Cycle client request GET /perl-status HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Cache-Control: no-cache Connection: Keep-Alive, TE Host: User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera [en]

36 Apache Request Cycle client request GET /perl-status HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Cache-Control: no-cache Connection: Keep-Alive, TE Host: User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera [en]

37 Apache Request Cycle client request URI-based init

38 Apache Request Cycle client request URI-based init URI translation

39 Apache Request Cycle client request URI-based init URI translation
file-based init

40 Apache Request Cycle client request URI-based init URI translation
file-based init resource control

41 Apache Request Cycle client request URI-based init URI translation
file-based init MIME setting resource control

42 Apache Request Cycle client request URI-based init URI translation
fixups file-based init MIME setting resource control

43 Apache Request Cycle client request URI-based init content
URI translation fixups file-based init MIME setting resource control

44 Apache Request Cycle content HTTP/1.1 200 OK
Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html

45 Apache Request Cycle content HTTP/1.1 200 OK
Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html

46 Apache Request Cycle content HTTP/1.1 200 OK
Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html

47 Apache Request Cycle client request URI-based init content
URI translation fixups file-based init MIME setting resource control

48 Apache Request Cycle client request logging URI-based init content
URI translation fixups file-based init MIME setting resource control

49 Apache Request Cycle client request logging URI-based init content
URI translation fixups file-based init MIME setting resource control

50 So What? most Apache users don't worry about the request cycle too much...

51 So What? most Apache users don't worry about the request cycle too much... ...but they do use modules that plug into it

52 ... for instance mod_rewrite:
client request URI-based init mod_rewrite: RewriteRule /favicon.ico$ /images/favicon.ico URI translation

53 ... for instance mod_auth: AuthUserFile .htpasswd client request
URI-based init URI translation file-based init mod_auth: AuthUserFile .htpasswd resource control

54 ... for instance mod_cgi: SetHandler cgi-script client request
URI-based init content URI translation fixups file-based init MIME setting resource control

55 That's great breaking down the request into distinct phases has many benefits

56 That's great breaking down the request into distinct phases has many benefits gives each processing point a role that can be easily managed and programmed

57 That's great breaking down the request into distinct phases has many benefits gives each processing point a role that can be easily managed and programmed makes Apache more like an application framework rather than a content engine

58 That's great, but... breaking down the request into distinct phases has many benefits gives each processing point a role that can be easily managed and programmed makes Apache more like an application framework rather than a content engine but you have to code in C

59 Enter mod_perl

60 Enter mod_perl mod_perl offers an interface to each phase of the request cycle

61 Enter mod_perl mod_perl offers an interface to each phase of the request cycle opens up the Apache API to Perl code

62 Enter mod_perl mod_perl offers an interface to each phase of the request cycle opens up the Apache API to Perl code allows you to program targeted parts of the request cycle using Perl

63 Enter mod_perl mod_perl offers an interface to each phase of the request cycle opens up the Apache API to Perl code allows you to program targeted parts of the request cycle using Perl we like Perl

64 Apache Request Cycle client request logging URI-based init content
URI translation fixups file-based init MIME setting resource control

65 mod_perl Interface client request PerlCleanupHandler PerlLogHandler
PerlPostReadRequestHandler logging URI-based init PerlHandler PerlTransHandler content URI translation PerlFixupHandler PerlHeaderParserHandler fixups file-based init PerlAccessHandler PerlAuthenHandler PerlAuthzHandler PerlTypeHandler MIME setting resource control

66 mod_perl Interface world's ugliest slide client request
PerlCleanupHandler PerlLogHandler PerlPostReadRequestHandler world's ugliest slide logging URI-based init PerlHandler PerlTransHandler content URI translation PerlFixupHandler PerlHeaderParserHandler fixups file-based init PerlAccessHandler PerlAuthenHandler PerlAuthzHandler PerlTypeHandler MIME setting resource control

67 mod_perl Interface client request PerlCleanupHandler PerlLogHandler
PerlPostReadRequestHandler logging URI-based init PerlHandler PerlTransHandler content URI translation PerlFixupHandler PerlHeaderParserHandler fixups file-based init PerlAccessHandler PerlAuthenHandler PerlAuthzHandler PerlTypeHandler MIME setting resource control

68 How?

69 How? mod_perl embeds an entire perl interpreter into Apache

70 Why?

71 Why? create a persistent perl environment

72 Why? create a persistent perl environment increase performance

73 Why? create a persistent perl environment
increase performance * (for the dynamic parts)

74 Why? create a persistent perl environment open up the Apache API
increase performance * (for the dynamic parts) open up the Apache API

75 Why? create a persistent perl environment open up the Apache API
increase performance * (for the dynamic parts) open up the Apache API increase developer options

76 Why? create a persistent perl environment open up the Apache API
increase performance * (for the dynamic parts) open up the Apache API increase developer options because it's cool

77 What is mod_perl?

78 What is mod_perl? to the masses, mod_perl is just faster CGI a la Apache::Registry

79 What is mod_perl? to the masses, mod_perl is just faster CGI a la Apache::Registry leads to comparisons to FastCGI, PerlEx, and other CGI enhancement engines

80 What is mod_perl? to the masses, mod_perl is just faster CGI a la Apache::Registry leads to comparisons to FastCGI, PerlEx, and other CGI enhancement engines not an accurate description of mod_perl, so comparisons aren't really valid

81 What is mod_perl?

82 What is mod_perl? mod_perl is the Perl interface to the Apache API

83 What is mod_perl? mod_perl is the Perl interface to the Apache API
a C extension module, just like mod_cgi or mod_rewrite

84 What is mod_perl? mod_perl is the Perl interface to the Apache API
a C extension module, just like mod_cgi or mod_rewrite creates a persistent perl environment embedded within Apache

85 What's the Big Deal?

86 What's the Big Deal? mod_perl allows you to interact with and directly alter server behavior

87 What's the Big Deal? mod_perl allows you to interact with and directly alter server behavior gives you the ability to "program within Apache's framework instead of around it"

88 What's the Big Deal? mod_perl allows you to interact with and directly alter server behavior gives you the ability to "program within Apache's framework instead of around it" let's you do it in Perl instead of C

89 What's the Big Deal? mod_perl allows you to interact with and directly alter server behavior gives you the ability to "program within Apache's framework instead of around it" let's you do it in Perl instead of C allows you to intercept basic Apache functions and replace them with your own (sometimes devious) Perl substitutes

90 Ok, so what's a handler?

91 Ok, so what's a handler? the term handler refers to processing that occurs during any of the Apache runtime phases

92 Ok, so what's a handler? the term handler refers to processing that occurs during any of the Apache runtime phases this includes the request-time phases as well as the other parts of the Apache runtime, such as restarts

93 Ok, so what's a handler? the term handler refers to processing that occurs during any of the Apache runtime phases this includes the request-time phases as well as the other parts of the Apache runtime, such as restarts the use of "handler" for all processing hooks is mod_perl specific

94 Why use handlers?

95 Why use handlers? gives each processing point a role that can be easily managed and programmed

96 Why use handlers? gives each processing point a role that can be easily managed and programmed process request at the proper phase meaningful access to the Apache API break up processing into smaller parts modularize and encapsulate processing

97 Why use handlers? gives each processing point a role that can be easily managed and programmed process request at the proper phase meaningful access to the Apache API break up processing into smaller parts modularize and encapsulate processing makes Apache more like an application framework rather than a content engine

98 Why use handlers? gives each processing point a role that can be easily managed and programmed process request at the proper phase meaningful access to the Apache API break up processing into smaller parts modularize and encapsulate processing makes Apache more like an application framework rather than a content engine CPAN

99

100 Registry is just a handler

101 Registry is just a handler
Apache::Registry is merely an (incredibly clever and amazing) mod_perl handler

102 Registry is just a handler
Apache::Registry is merely an (incredibly clever and amazing) mod_perl handler its performance gains are made possible due to what mod_perl really is

103 Registry is just a handler
Apache::Registry is merely an (incredibly clever and amazing) mod_perl handler its performance gains are made possible due to what mod_perl really is let's take a peek inside...

104 Apache::Registry

105 Apache::Registry Client side http://localhost/perl-bin/bar.pl

106 Apache::Registry Client side Server side
Server side

107 Apache::Registry Client side Server side
Server side mod_perl intercepts content generation

108 Apache::Registry Client side Server side
Server side mod_perl intercepts content generation for Apache/Registry.pm

109 Apache::Registry Client side Server side
Server side mod_perl intercepts content generation for Apache/Registry.pm calls Apache::Registry::handler(Apache->request)

110 Apache::Registry Client side Server side
Server side mod_perl intercepts content generation for Apache/Registry.pm calls Apache::Registry::handler(Apache->request) inserts wizardry

111 Apache::Registry Client side Server side
Server side mod_perl intercepts content generation for Apache/Registry.pm calls Apache::Registry::handler(Apache->request) inserts wizardry returns response to client

112 Wizardry, you say?

113 Wizardry, you say? the wizardry is basically just putting the CGI script into it's own package

114 Wizardry, you say? the wizardry is basically just putting the CGI script into it's own package package Apache::ROOT::perl_2dbin::foo_2epl; sub handler { BEGIN { $^W = 1; }; ... your script here... } 1;

115 Wizardry, you say? the wizardry is basically just putting the CGI script into it's own package package Apache::ROOT::perl_2dbin::foo_2epl; sub handler { BEGIN { $^W = 1; }; ... your script here... } 1;

116 Wizardry, you say? the wizardry is basically just putting the CGI script into it's own package package Apache::ROOT::perl_2dbin::foo_2epl; sub handler { BEGIN { $^W = 1; }; ... your script here... } 1;

117 Wizardry, you say? the wizardry is basically just putting the CGI script into it's own package package Apache::ROOT::perl_2dbin::foo_2epl; sub handler { BEGIN { $^W = 1; }; ... your script here... } 1; because the perl interpreter is persistent the (compiled) package is already in memory when called

118 "The dream is always the same"

119 "The dream is always the same"

120 "The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry)

121 "The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl

122 "The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl mod_perl passes control to your Perl handler

123 "The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl mod_perl passes control to your Perl handler your Perl subroutine defines the status

124 "The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl mod_perl passes control to your Perl handler your Perl subroutine defines the status mod_perl passes status back to Apache

125 "The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl mod_perl passes control to your Perl handler your Perl subroutine defines the status mod_perl passes status back to Apache Apache continues along

126 Anatomy of a Handler

127 Anatomy of a Handler a mod_perl handler is just an ordinary Perl module

128 Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible

129 Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible including mod_perl extra paths

130 Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible including mod_perl extra paths contains a package declaration

131 Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible including mod_perl extra paths contains a package declaration has at least one subroutine

132 Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible including mod_perl extra paths contains a package declaration has at least one subroutine typically the handler() subroutine

133 Let's create a handler...

134 Let's create a handler... Object: to protect our name-based virtual hosts from proper but bad HTTP/1.0 requests

135 Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests

136 HTTP/1.0 and Host

137 HTTP/1.0 and Host HTTP/1.0 does not require a Host header

138 HTTP/1.0 and Host HTTP/1.0 does not require a Host header
assumes a “one host per IP" configuration

139 HTTP/1.0 and Host HTTP/1.0 does not require a Host header
assumes a “one host per IP" configuration this limitation "breaks" name-based virtual host servers for browsers that follow HTTP/1.0 to the letter

140 HTTP/1.0 and Host HTTP/1.0 does not require a Host header
assumes a “one host per IP" configuration this limitation "breaks" name-based virtual host servers for browsers that follow HTTP/1.0 to the letter most send the Host header, so all is well

141 Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 HTTP/ Found Date: Tue, 04 Jun :52:55 GMT Server: Apache/ dev (Unix) Location: Content-Length: 289 Connection: close Content-Type: text/html; charset=iso <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>302 Found</title> </head><body> <h1>Found</h1> <p>The document has moved <a href=" <hr /> <address>Apache/ dev Server at dev.apache.org Port 80</address> </body></html> Connection closed by foreign host.

142 Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 HTTP/ Found Date: Tue, 04 Jun :52:55 GMT Server: Apache/ dev (Unix) Location: Content-Length: 289 Connection: close Content-Type: text/html; charset=iso <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>302 Found</title> </head><body> <h1>Found</h1> <p>The document has moved <a href=" /> <address>Apache/ dev Server at dev.apache.org Port 80</address> </body></html> Connection closed by foreign host.

143 Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 HTTP/ Found Date: Tue, 04 Jun :52:55 GMT Server: Apache/ dev (Unix) Location: Content-Length: 289 Connection: close Content-Type: text/html; charset=iso <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>302 Found</title> </head><body> <h1>Found</h1> <p>The document has moved <a href=" <hr /> <address>Apache/ dev Server at dev.apache.org Port 80</address> </body></html> Connection closed by foreign host.

144 Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 Host: HTTP/ Not Found Date: Tue, 04 Jun :56:40 GMT Server: Apache/ dev (Unix) Content-Length: 283 Content-Type: text/html; charset=iso <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL /foo.html was not found on this server.</p> <hr /> <address>Apache/ dev Server at Port 80</address> </body></html>

145 Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 Host: HTTP/ Not Found Date: Tue, 04 Jun :56:40 GMT Server: Apache/ dev (Unix) Content-Length: 283 Content-Type: text/html; charset=iso <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL /foo.html was not found on this server.</p> <hr /> <address>Apache/ dev Server at Port 80</address> </body></html>

146 Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 Host: HTTP/ Not Found Date: Tue, 04 Jun :56:40 GMT Server: Apache/ dev (Unix) Content-Length: 283 Content-Type: text/html; charset=iso <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL /foo.html was not found on this server.</p> <hr /> <address>Apache/ dev Server at Port 80</address> </body></html>

147 Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests

148 Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests Method: intercept the request prior to content-generation and return an error unless...

149 Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests Method: intercept the request prior to content-generation and return an error unless... there is a Host header

150 Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests Method: intercept the request prior to content-generation and return an error unless... there is a Host header the request is an absolute URI

151 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

152 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

153 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

154 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

155 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

156 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

157 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

158 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = Apache->request; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

159 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

160 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

161 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

162 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

163 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

164 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

165 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

166 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

167 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

168 Setup add TrapNoHost.pm

169 Setup add TrapNoHost.pm to @INC
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm

170 Setup add TrapNoHost.pm to @INC add to httpd.conf
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf

171 Setup add TrapNoHost.pm to @INC add to httpd.conf
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlTransHandler Cookbook::TrapNoHost

172 Setup add TrapNoHost.pm to @INC add to httpd.conf
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlTransHandler Cookbook::TrapNoHost

173 Setup add TrapNoHost.pm to @INC add to httpd.conf
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlTransHandler Cookbook::TrapNoHost

174 Setup add TrapNoHost.pm to @INC add to httpd.conf that's it!
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlTransHandler Cookbook::TrapNoHost that's it!

175 Apache Request Cycle client request client request logging
URI-based init content URI translation fixups file-based init MIME setting resource control

176 Intercept the Request client request URI-based init URI translation

177 Intercept the Request client request URI-based init URI translation
HTTP/ Bad Request Date: Tue, 04 Jun :17:52 GMT Server: Apache/ dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0 Connection: close Content-Type: text/html; charset=iso Oops! Did you mean to omit a Host header?

178 Intercept the Request client request URI-based init URI translation
HTTP/ Bad Request Date: Tue, 04 Jun :17:52 GMT Server: Apache/ dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0 Connection: close Content-Type: text/html; charset=iso Oops! Did you mean to omit a Host header?

179 Intercept the Request client request logging URI-based init
URI translation

180

181 Key Concepts

182 Key Concepts the Apache request object, $r

183 Key Concepts the Apache request object, $r the Apache::Table class

184 Key Concepts the Apache request object, $r the Apache::Table class
the Apache::URI class

185 Key Concepts the Apache request object, $r the Apache::Table class
the Apache::URI class return values and the Apache::Constants class

186 Key Concepts the Apache request object, $r the Apache::Table class
the Apache::URI class return values and the Apache::Constants class error responses and $r‑>custom_response()

187 Apache Request Object

188 Apache Request Object passed to handlers or available via Apache->request()

189 Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler()

190 Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request();

191 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

192 Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request();

193 Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request(); provides access to the Apache class, which provides access to request attributes

194 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

195 Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request(); provides access to the Apache class, which provides access to request attributes

196 Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request(); provides access to the Apache class, which provides access to request attributes singleton-like constructor, always returning the same object

197 Apache::Table

198 Apache::Table the Apache::Table class provides the underlying API for the following request attributes...

199 Apache::Table the Apache::Table class provides the underlying API for the following request attributes... $r->headers_in() $r->headers_out() $r->err_headers_out() $r->dir_config() $r->subprocess_env() $r->notes() Apache::Request::param() Apache::Request::parms() in old releases

200 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

201 Apache::Table to manipulate Apache::Table objects, you use the provided methods

202 Apache::Table to manipulate Apache::Table objects, you use the provided methods get() set() add() unset() do() merge() new() clear()

203 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

204 Apache Table Properties

205 Apache Table Properties
Apache tables have some nice properties

206 Apache Table Properties
Apache tables have some nice properties case insensitive

207 Apache Table Properties
Apache tables have some nice properties case insensitive allow for multi-valued keys

208 Apache Table Properties
Apache tables have some nice properties case insensitive allow for multi-valued keys they also have one important limitation

209 Apache Table Properties
Apache tables have some nice properties case insensitive allow for multi-valued keys they also have one important limitation can contain only simple strings

210 Apache Table Properties
Apache tables have some nice properties case insensitive allow for multi-valued keys they also have one important limitation can contain only simple strings use pnotes() for Perl scalars

211 keeps the Net flowin'...

212 keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers

213 keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers $r->headers_out->set('Set-Cookie' => 'name=foo');

214 keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers $r->headers_out->set('Set-Cookie' => 'name=foo'); $r->headers_out->add('set-cookie' => 'name=bar');

215 keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers $r->headers_out->set('Set-Cookie' => 'name=foo'); $r->headers_out->add('set-cookie' => 'name=bar'); = $r->headers_out->get('Set-cookie');

216 Table Iteration

217 Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table

218 Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });

219 Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });

220 Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });

221 Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });

222 Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });

223 Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });

224 Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });

225 More Apache::Table Fun

226 More Apache::Table Fun
Tired

227 More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok"

228 More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok" my $ok = $r->dir_config('MyVar');

229 More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok" my $ok = $r->dir_config('MyVar'); Wired

230 More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok" my $ok = $r->dir_config('MyVar'); Wired PerlAddVar MyVar "cool"

231 More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok" my $ok = $r->dir_config('MyVar'); Wired PerlAddVar MyVar "cool" = $r->dir_config->get('MyVar');

232 Trickery

233 Trickery really understanding the Apache::Table class will make you a better mod_perl programmer

234 Trickery really understanding the Apache::Table class will make you a better mod_perl programmer every table can be set

235 Trickery really understanding the Apache::Table class will make you a better mod_perl programmer every table can be set $r->headers_in() $r->headers_out() $r->err_headers_out() $r->dir_config() $r->subprocess_env() $r->notes() Apache::Request::param()

236 Trickery handle "what if?" cases

237 Trickery handle "what if?" cases
$r->headers_in->set('Set-Cookie' => 'name=foo'); my $sub = $r->lookup_uri('/scripts/foo.html');

238 Trickery handle "what if?" cases gratuitous exploitation
$r->headers_in->set('Set-Cookie' => 'name=foo'); my $sub = $r->lookup_uri('/scripts/foo.html'); gratuitous exploitation

239 Trickery handle "what if?" cases gratuitous exploitation
$r->headers_in->set('Set-Cookie' => 'name=foo'); my $sub = $r->lookup_uri('/scripts/foo.html'); gratuitous exploitation # configure "PerlSetVar Filter On" on-the-fly $r->dir_config->set(Filter => 'On');

240 All About URIs

241 All About URIs when Apache parses the incoming request, it puts parts of the URI into the request record

242 All About URIs when Apache parses the incoming request, it puts parts of the URI into the request record for just digging out the request URI you typically want the request attribute $r->uri()

243 All About URIs when Apache parses the incoming request, it puts parts of the URI into the request record for just digging out the request URI you typically want the request attribute $r->uri() my $uri = $r->uri; # $uri is "/index.html"

244 All About URIs when Apache parses the incoming request, it puts parts of the URI into the request record for just digging out the request URI you typically want the request attribute $r->uri() my $uri = $r->uri; # $uri is "/index.html" sometimes you need all the URI parts, like the scheme or port

245 Apache::URI

246 Apache::URI mod_perl provides the Apache::URI utility class for handling URIs

247 Apache::URI mod_perl provides the Apache::URI utility class for handling URIs allows for manipulating the current URI as well as constructing a new URI

248 Apache::URI mod_perl provides the Apache::URI utility class for handling URIs allows for manipulating the current URI as well as constructing a new URI unfortunately, it has two distinct interfaces that contain very subtle differences

249 Apache::URI mod_perl provides the Apache::URI utility class for handling URIs allows for manipulating the current URI as well as constructing a new URI unfortunately, it has two distinct interfaces that contain very subtle differences our code uses those differences to our advantage

250 Manipulating URIs

251 Manipulating URIs Apache::URI offers the parse() method as a constructor

252 Manipulating URIs Apache::URI offers the parse() method as a constructor my $uri = Apache::URI->parse($r);

253 Manipulating URIs Apache::URI offers the parse() method as a constructor my $uri = Apache::URI->parse($r); you can also grab an Apache::URI object from the request itself my $uri = $r->parsed_uri;

254 Manipulating URIs Apache::URI offers the parse() method as a constructor my $uri = Apache::URI->parse($r); you can also grab an Apache::URI object from the request itself my $uri = $r->parsed_uri; to get the URI string back, call the unparse() method

255 Manipulating URIs Apache::URI offers the parse() method as a constructor my $uri = Apache::URI->parse($r); you can also grab an Apache::URI object from the request itself my $uri = $r->parsed_uri; to get the URI string back, call the unparse() method $uri->path('/new/location'); $r->headers_out->set(Location => $uri->unparse);

256 Apache::URI methods

257 Apache::URI methods once you have an Apache::URI object, you can peek at or modify any part of the URI using its accessor methods

258 Apache::URI methods once you have an Apache::URI object, you can peek at or modify any part of the URI using its accessor methods - password() - port() - scheme() - path() - query() - more...

259 Apache::URI methods once you have an Apache::URI object, you can peek at or modify any part of the URI using its accessor methods - password() - port() - scheme() - path() - query() - more... unfortunately, although the objects have the same methods, they don't always behave the same...

260 parsed_uri()

261 parsed_uri() parsed_uri() returns an object populated based on $r->uri() and other parts of the request record

262 parsed_uri() parsed_uri() returns an object populated based on $r->uri() and other parts of the request record since the URI has undergone translation, the path_info() method will return useful information

263 parsed_uri() parsed_uri() returns an object populated based on $r->uri() and other parts of the request record since the URI has undergone translation, the path_info() method will return useful information Given: <Location /foo>

264 parsed_uri() parsed_uri() returns an object populated based on $r->uri() and other parts of the request record since the URI has undergone translation, the path_info() method will return useful information Given: <Location /foo> my $path = $r->parsed_uri->path; # "/foo" my $info = $r->parsed_uri->path_info; # "/bar"

265 Apache::URI->parse($r)

266 Apache::URI->parse($r)
Apache::URI->parse($r) only looks at the incoming URI and makes no assumptions about the underlying filesystem

267 Apache::URI->parse($r)
Apache::URI->parse($r) only looks at the incoming URI and makes no assumptions about the underlying filesystem Given: <Location /foo>

268 Apache::URI->parse($r)
Apache::URI->parse($r) only looks at the incoming URI and makes no assumptions about the underlying filesystem Given: <Location /foo> my $path = Apache::URI->parse($r)->path; # "/foo/bar" my $info = Apache::URI->parse($r)->path_info; # undef

269 parsed_uri()

270 parsed_uri() unless the request is an absolute URI the scheme, host, and port fields will be absent

271 parsed_uri() unless the request is an absolute URI the scheme, host, and port fields will be absent proxy requests are absolute URIs

272 parsed_uri() unless the request is an absolute URI the scheme, host, and port fields will be absent proxy requests are absolute URIs Given:

273 Apache::URI->parse($r)

274 Apache::URI->parse($r)
Apache::URI->parse($r) uses other bits of information to construct a self-referential URI

275 Apache::URI->parse($r)
Apache::URI->parse($r) uses other bits of information to construct a self-referential URI Given:

276 Apache::URI->parse($r)
Apache::URI->parse($r) uses other bits of information to construct a self-referential URI Given: my $scheme = Apache::URI->parse($r)->scheme; # "http" my $host = Apache::URI->parse($r)->hostname; "

277 it all boils down to...

278 it all boils down to... the differences between Apache::URI->parse($r) and $r->parsed_uri() are very confusing

279 it all boils down to... the differences between Apache::URI->parse($r) and $r->parsed_uri() are very confusing use Apache::URI->parse($r) for creating a self-referential URI that needs to point to the same server

280 it all boils down to... the differences between Apache::URI->parse($r) and $r->parsed_uri() are very confusing use Apache::URI->parse($r) for creating a self-referential URI that needs to point to the same server use $r->parsed_uri() for accessing request attributes

281 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

282 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

283 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

284 Apache::Constants

285 Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST);

286 Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are:

287 Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK

288 Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK SERVER_ERROR

289 Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK SERVER_ERROR REDIRECT

290 Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK SERVER_ERROR REDIRECT DECLINED

291 Return Values handlers are expected to return a value

292 Return Values handlers are expected to return a value
the return value of the handler defines the status of the request

293 Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values

294 Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values OK – all is well

295 Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values OK – all is well DECLINED – forget about me

296 Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values OK – all is well DECLINED – forget about me DONE – we're finished, start to log

297 Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values OK – all is well DECLINED – forget about me DONE – we're finished, start to log All other values are "errors" and trigger the ErrorDocument cycle

298 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

299 When handlers turn bad...

300 When handlers turn bad... "error" return codes are not always errors

301 When handlers turn bad... "error" return codes are not always errors
instead, they indicate a new route for the request

302 package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1;

303 package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1;

304 package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1;

305 package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1; <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <HTML><HEAD> <TITLE>302 Found</TITLE> </HEAD><BODY> <H1>Found</H1> The document has moved <A HREF="/foo">here</A>.<P> <HR> <ADDRESS>Apache/ dev Server at mainsheet.laserlink.com Port 80</ADDRESS> </BODY></HTML>

306 package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1; <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <HTML><HEAD> <TITLE>302 Found</TITLE> </HEAD><BODY> <H1>Found</H1> The document has moved <A HREF="/foo">here</A>.<P> <HR> <ADDRESS>Apache/ dev Server at mainsheet.laserlink.com Port 80</ADDRESS> </BODY></HTML>

307 Custom Responses

308 Custom Responses Apache has default responses for most of the possible errors

309 Custom Responses Apache has default responses for most of the possible errors it also provides the ErrorDocument directive for fine-tuning server behavior

310 Custom Responses Apache has default responses for most of the possible errors it also provides the ErrorDocument directive for fine-tuning server behavior you can specify error behavior on-the-fly with custom_response()

311 custom_response()

312 custom_response() the custom_response() method has several interfaces...

313 custom_response() the custom_response() method has several interfaces... # set the response for 500 $r->custom_response(SERVER_ERROR, '/error.html')

314 custom_response() the custom_response() method has several interfaces... # set the response for 500 $r->custom_response(SERVER_ERROR, '/error.html') # capture the current 500 setting my $errordoc = $r->custom_response(SERVER_ERROR)

315 custom_response() the custom_response() method has several interfaces... # set the response for 500 $r->custom_response(SERVER_ERROR, '/error.html') # capture the current 500 setting my $errordoc = $r->custom_response(SERVER_ERROR) # reset 500 back to the Apache default $r->custom_response(SERVER_ERROR, undef);

316 package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1;

317 Key Concepts the Apache request object, $r the Apache::Table class
the Apache::URI class return values and the Apache::Constants class error responses and $r‑>custom_response()

318

319 Just the Beginning

320 Just the Beginning almost every part of Apache's default behavior can be replaced, rewritten, or extended using mod_perl

321 Just the Beginning almost every part of Apache's default behavior can be replaced, rewritten, or extended using mod_perl in many cases you can do much more than you can with Apache and C due to Perl's ability to fold, spindle, and mutilate everyday items

322 User Authentication

323 User Authentication Apache default authentication mechanism is mod_auth

324 User Authentication Apache default authentication mechanism is mod_auth uses a password file generated using Apache's htpasswd utility

325 User Authentication Apache default authentication mechanism is mod_auth uses a password file generated using Apache's htpasswd utility geoff:zzpEyL0tbgwwk

326 User Authentication configuration placed in .htaccess file or httpd.conf

327 User Authentication configuration placed in .htaccess file or httpd.conf AuthUserFile .htpasswd AuthName "my site" AuthType Basic Require valid-user

328 User Authentication configuration placed in .htaccess file or httpd.conf AuthUserFile .htpasswd AuthName "my site" AuthType Basic Require valid-user

329 Who Uses Flat Files?

330 Who Uses Flat Files? flat files are limiting, hard to manage, difficult to integrate, and just plain boring

331 Who Uses Flat Files? flat files are limiting, hard to manage, difficult to integrate, and just plain boring we can use the Apache API and Perl to replace flat files with our own authentication mechanism

332 How Authentication Works
client requests a document

333 How Authentication Works
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US)

334 How Authentication Works
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request

335 How Authentication Works
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request HTTP/ Authorization Required WWW-Authenticate: Basic realm="my site" Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=iso

336 How Authentication Works
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request HTTP/ Authorization Required WWW-Authenticate: Basic realm="my site" Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=iso

337 How Authentication Works
client request client request logging URI-based init content URI translation fixups file-based init MIME setting resource control

338 How Authentication Works
client request client request URI-based init URI translation file-based init resource control resource control

339 How Authentication Works
client request client request URI-based init URI translation file-based init resource control resource control HTTP/ Authorization Required

340 How Authentication Works
client request client request logging URI-based init URI translation file-based init resource control resource control

341 How Authentication Works
client sends a new request

342 How Authentication Works
client sends a new request GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Authorization: Basic Z2VvZmY6YWZha2VwYXNzd29yZA== Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US)

343 How Authentication Works
client sends a new request GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Authorization: Basic Z2VvZmY6YWZha2VwYXNzd29yZA== Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US)

344 How Authentication Works
client sends a new request GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Authorization: Basic Z2VvZmY6YWZha2VwYXNzd29yZA== Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server sends document

345 How Authentication Works
client sends a new request GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Authorization: Basic Z2VvZmY6YWZha2VwYXNzd29yZA== Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server sends document HTTP/ OK Keep-Alive: timeout=15, max=99 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html

346 Do it in Perl since mod_perl gives us the ability to intercept the request cycle before Apache, we can authenticate using Perl instead

347 Do it in Perl since mod_perl gives us the ability to intercept the request cycle before Apache, we can authenticate using Perl instead Apache provides an API, making the job easy

348 Do it in Perl since mod_perl gives us the ability to intercept the request cycle before Apache, we can authenticate using Perl instead Apache provides an API, making the job easy mod_perl provides access to the Apache API

349 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

350 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

351 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

352 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

353 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

354 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

355 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

356 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

357 No Authorization Header
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request HTTP/ Authorization Required WWW-Authenticate: Basic realm="my site" Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=iso

358 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

359 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

360 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

361 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

362 package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; }

363 Configuration

364 Configuration change AuthUserFile .htpasswd AuthName "my site"
AuthType Basic Require valid-user

365 Configuration change to AuthUserFile .htpasswd AuthName "my site"
AuthType Basic Require valid-user to PerlAuthenHandler My::Authenticate

366 Configuration change to AuthUserFile .htpasswd AuthName "my site"
AuthType Basic Require valid-user to PerlAuthenHandler My::Authenticate

367 The Choice is Yours how you decide to authenticate is now up to you

368 The Choice is Yours how you decide to authenticate is now up to you
sub authenticate_user { my ($user, $pass) return $user eq $pass; }

369 The Choice is Yours how you decide to authenticate is now up to you
sub authenticate_user { my ($user, $pass) return $user eq $pass; } are you seeing the possibilities yet?

370 The Power of CPAN over 25 Apache:: shrink-wrapped modules on CPAN for authentication SecureID Radius SMB LDAP NTLM

371 To Infinity and Beyond!

372 To Infinity and Beyond!

373 To Infinity and Beyond! this example only covered Basic authentication via popup box

374 To Infinity and Beyond! this example only covered Basic authentication via popup box the same techniques can be used to authenticate via a login form plus cookies, munged URLs, or hidden fields

375 To Infinity and Beyond! this example only covered Basic authentication via popup box the same techniques can be used to authenticate via a login form plus cookies, munged URLs, or hidden fields extended to use Digest authentication as well

376

377 Content Generation client request logging URI-based init content
URI translation fixups file-based init MIME setting resource control

378 Sample PerlHandler create a handler that uses CPAN module HTML::Clean to "clean" outgoing documents

379 Sample PerlHandler create a handler that uses CPAN module HTML::Clean to "clean" outgoing documents alter the handler to take advantage of more advanced mod_perl features

380 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

381 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

382 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

383 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

384 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

385 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

386 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

387 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

388 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

389 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

390 use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

391 Configuration add directives to httpd.conf to mirror DocumentRoot
Alias /clean /usr/local/apache/htdocs <Location /clean> SetHandler perl-script PerlHandler TPC::Clean </Location>

392 Results original: 202 bytes <html> <body>
<form method="GET" action="/foo"> Text: <input type="text" name="foo"><br> <input type="submit"> </form> <strong>hi there </strong> </body> </html>

393 Results original: 202 bytes clean: 145 bytes <html> <body>
<form method="GET" action="/foo"> Text: <input type="text" name="foo"><br> <input type="submit"> </form> <strong>hi there </strong> </body> </html> clean: 145 bytes <html><body><form method="GET" action="/foo"> Text: <input type="text" name="foo"><br><input type="submit"></form><b>hi there </b></body></html>

394 Results original: 202 bytes clean: 145 bytes <html> <body>
<form method="GET" action="/foo"> Text: <input type="text" name="foo"><br> <input type="submit"> </form> <strong>hi there </strong> </body> </html> clean: 145 bytes <html><body><form method="GET" action="/foo"> Text: <input type="text" name="foo"><br><input type="submit"></form><b>hi there </b></body></html>

395 Key Concepts

396 Key Concepts Apache::File class

397 Key Concepts Apache::File class $r->filename

398 Key Concepts Apache::File class $r->filename local $/

399 Apache::File

400 Apache::File Apache::File is similar to IO::File

401 Apache::File Apache::File is similar to IO::File
my $fh = Apache::File->new($r->filename); while (my $line = <$fh>) { ... }

402 Apache::File Apache::File is similar to IO::File
my $fh = Apache::File->new($r->filename); while (my $line = <$fh>) { ... } it also adds a number of methods to the Apache class for use when manipulating files over HTTP

403 $r->filename()

404 $r->filename() contains the result of URI-to-filename translation

405 $r->filename() contains the result of URI-to-filename translation
if you just want to stat() the requested file, use $r->finfo and the special filehandle _

406 $r->filename() contains the result of URI-to-filename translation
if you just want to stat() the requested file, use $r->finfo and the special filehandle _ if (-f $r->finfo && -M _ < $timeout) { ... }

407 local $/;

408 local $/; typical Perl idiom

409 local $/; typical Perl idiom local $/; my $file = <$fh>; #slurp

410 local $/; typical Perl idiom local $/; my $file = <$fh>; #slurp
my $file = do {local $/; <$fh>};

411 local $/; typical Perl idiom bad under mod_perl local $/;
my $file = <$fh>; #slurp my $file = do {local $/; <$fh>}; bad under mod_perl

412 local $/; typical Perl idiom bad under mod_perl
my $file = <$fh>; #slurp my $file = do {local $/; <$fh>}; bad under mod_perl but we do it anyway with justification

413 The Choice is Yours!

414 The Choice is Yours! Content filtering with Apache::Filter?

415 The Choice is Yours! Content filtering with Apache::Filter?
Using proper cache-friendly headers?

416 Magic

417 Magic filtered content generation impossible with Apache 1.3

418 Magic filtered content generation impossible with Apache 1.3
can't send CGI output through mod_ssi

419 Magic filtered content generation impossible with Apache 1.3
can't send CGI output through mod_ssi reason for output filters in Apache 2.0

420 Magic filtered content generation impossible with Apache 1.3
can't send CGI output through mod_ssi reason for output filters in Apache 2.0 mod_perl has had output filtering for years

421 Magic filtered content generation impossible with Apache 1.3
can't send CGI output through mod_ssi reason for output filters in Apache 2.0 mod_perl has had output filtering for years possible due to Perl's TIEHANDLE interface

422 TIEHANDLE in mod_perl

423 TIEHANDLE in mod_perl mod_perl tie()s STDOUT to the Apache class prior to the content generation phase

424 TIEHANDLE in mod_perl mod_perl tie()s STDOUT to the Apache class prior to the content generation phase you can tie() STDOUT as well and override mod_perl's default behavior

425 TIEHANDLE in mod_perl mod_perl tie()s STDOUT to the Apache class prior to the content generation phase you can tie() STDOUT as well and override mod_perl's default behavior very useful with stacked handlers

426 Stacked Handlers

427 Stacked Handlers for each phase of the request, mod_perl will run any registered Perl handlers for that phase

428 Stacked Handlers for each phase of the request, mod_perl will run any registered Perl handlers for that phase you can register more than one Perl handler per phase

429 Stacked Handlers for each phase of the request, mod_perl will run any registered Perl handlers for that phase you can register more than one Perl handler per phase whether all handlers are called depends on the syntax of the phase itself in Apache

430 Stacked Handlers some phase run until the handler list is exhausted

431 Stacked Handlers some phase run until the handler list is exhausted
PerlLogHandler My::DBLogger PerlLogHandler My::FileLogger

432 Stacked Handlers some phase run until the handler list is exhausted
PerlLogHandler My::DBLogger PerlLogHandler My::FileLogger some phases run until one handler returns OK

433 Stacked Handlers some phase run until the handler list is exhausted
PerlLogHandler My::DBLogger PerlLogHandler My::FileLogger some phases run until one handler returns OK PerlTransHandler My::TranslateHTML PerlTransHandler My::TranslateText

434 Stacked Handlers some phase run until the handler list is exhausted
PerlLogHandler My::DBLogger PerlLogHandler My::FileLogger some phases run until one handler returns OK PerlTransHandler My::TranslateHTML PerlTransHandler My::TranslateText all phases terminate on "error"

435 Stacked Content Handlers

436 Stacked Content Handlers
for the content generation phase, running multiple Perl handlers can be incredibly powerful

437 Stacked Content Handlers
for the content generation phase, running multiple Perl handlers can be incredibly powerful Apache::Filter implements a simple interface for pipelining content handlers

438 Stacked Content Handlers
for the content generation phase, running multiple Perl handlers can be incredibly powerful Apache::Filter implements a simple interface for pipelining content handlers uses TIEHANDLE in the background

439 Now for the Fun Part

440 Now for the Fun Part modify our handler to work either standalone or as part of a handler chain

441 Now for the Fun Part modify our handler to work either standalone or as part of a handler chain easy using Apache::Filter

442 Apache::Filter Changes

443 Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED;

444 Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;

445 Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;

446 Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;

447 Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;

448 Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;

449 Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;

450 Configuration

451 Configuration change Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean </Location>

452 Configuration change to Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean </Location> to PerlModule Apache::Filter PerlSetVar Filter On

453 Configuration change to Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean </Location> to PerlModule Apache::Filter PerlSetVar Filter On

454 Key Concepts Apache::Filter API

455 Apache::Filter

456 Apache::Filter Apache::Filter adds methods to the Apache class

457 Apache::Filter Apache::Filter adds methods to the Apache class
do not have to use Apache::Filter;

458 Apache::Filter Apache::Filter adds methods to the Apache class
do not have to use Apache::Filter; do have to PerlModule Apache::Filter

459 Apache::Filter Apache::Filter adds methods to the Apache class
do not have to use Apache::Filter; do have to PerlModule Apache::Filter because filtering content is tricky, the interface is quirky

460 Apache::Filter Apache::Filter adds methods to the Apache class
do not have to use Apache::Filter; do have to PerlModule Apache::Filter because filtering content is tricky, the interface is quirky $r = $r->filter_register;

461 Apache::Filter to get at filtered input, call $r->filter_input()

462 Apache::Filter to get at filtered input, call $r->filter_input()
returns an open filehandle on the input stream

463 Apache::Filter to get at filtered input, call $r->filter_input()
returns an open filehandle on the input stream if the first filter, the filehandle is for $r->filename()

464 Apache::Filter to get at filtered input, call $r->filter_input()
returns an open filehandle on the input stream if the first filter, the filehandle is for $r->filename() all filters use the same API, regardless of their position in the chain

465 So What?

466 So What? new Apache::Filter aware code works the same as the standalone module

467 So What? new Apache::Filter aware code works the same as the standalone module can be used as part of a PerlHandler chain

468 So What? new Apache::Filter aware code works the same as the standalone module can be used as part of a PerlHandler chain can be any part of the chain

469 Compressing Output

470 Compressing Output use Apache::Compress

471 Compressing Output use Apache::Compress available from CPAN

472 Compressing Output use Apache::Compress available from CPAN
uses Compress::Zlib to compress output

473 Compressing Output use Apache::Compress available from CPAN
uses Compress::Zlib to compress output Apache::Filter aware

474 Configuration

475 Configuration change Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean PerlSetVar Filter On </Location>

476 Configuration change to Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean PerlSetVar Filter On </Location> to PerlHandler My::Clean Apache::Compress

477 Configuration change to Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean PerlSetVar Filter On </Location> to PerlHandler My::Clean Apache::Compress

478 Stacked Power http://perl.apache.org/index.html straight HTML
35668 bytes My::Clean 28162 bytes (79%) Apache::Compress 8177 bytes (23%) My::Clean + Apache::Compress 7458 bytes (21%)

479 Caveats

480 Caveats using Apache::Filter is actually a bit more complex than this...

481 Caveats using Apache::Filter is actually a bit more complex than this... see the recent version of Apache::Clean to get an idea

482 Cache Headers

483 Cache Headers we often think of dynamic content as "could be different on any given access"

484 Cache Headers we often think of dynamic content as "could be different on any given access" "dynamic" content can also be static with clearly defined factors that can change its meaning

485 Cache Headers we often think of dynamic content as "could be different on any given access" "dynamic" content can also be static with clearly defined factors that can change its meaning by properly managing HTTP/1.1 cache headers, we can reduce strain on our servers

486 Conditional GET Request

487 Conditional GET Request
HTTP/1.1 allows for a conditional GET request

488 Conditional GET Request
HTTP/1.1 allows for a conditional GET request clients are allowed to use cached content based on information about the resource

489 Conditional GET Request
HTTP/1.1 allows for a conditional GET request clients are allowed to use cached content based on information about the resource information is provided by both the client and the server

490 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Content-Length: 9268 Connection: close Content-Type: text/html

491 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Content-Length: 9268 Connection: close Content-Type: text/html

492 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Content-Length: 9268 Connection: close Content-Type: text/html

493 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ Not Modified Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Connection: close

494 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ Not Modified Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Connection: close

495 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ Not Modified Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Connection: close

496 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ Not Modified Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Connection: close

497 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close

498 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close

499 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close

500 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close

501 GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close

502 Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly

503 Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly since the file is on disk, Apache can determine when the file was last changed

504 Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly since the file is on disk, Apache can determine when the file was last changed with static files, local modification is the only factor

505 Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly since the file is on disk, Apache can determine when the file was last changed with static files, local modification is the only factor still too many rules to keep straight

506 Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly since the file is on disk, Apache can determine when the file was last changed with static files, local modification is the only factor still too many rules to keep straight Apache provides an API to use so we don't have to think too much

507 Now for the Fun Part

508 Now for the Fun Part modify our handler to be "cache friendly"

509 Now for the Fun Part modify our handler to be "cache friendly"
send 304 when the document hasn't changed

510 Now for the Fun Part modify our handler to be "cache friendly"
send 304 when the document hasn't changed properly handle If-* header comparisons

511 How do you define change?

512 How do you define change?

513 How do you define change?
when dynamically altering static documents there are a number of factors to consider

514 How do you define change?
when dynamically altering static documents there are a number of factors to consider when the file changes on disk

515 How do you define change?
when dynamically altering static documents there are a number of factors to consider when the file changes on disk when the code changes

516 How do you define change?
when dynamically altering static documents there are a number of factors to consider when the file changes on disk when the code changes when the options to the code changes

517 How do you define change?
when dynamically altering static documents there are a number of factors to consider when the file changes on disk when the code changes when the options to the code changes all of these affect the "freshness" of the document

518 Code Changes

519 Code Changes in order to determine when the code itself changes, we need to mark the modification time of the package

520 Code Changes in order to determine when the code itself changes, we need to mark the modification time of the package at request time, we call an API to compare the package modification to the If-Modified-Since header

521 Code Changes in order to determine when the code itself changes, we need to mark the modification time of the package at request time, we call an API to compare the package modification to the If-Modified-Since header on reloads, we regenerate the package modification time

522 use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;

523 use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9];

524 use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9];

525 Configuration Changes

526 Configuration Changes
in order to determine when the options to the code change, we need to mark the modification time of httpd.conf

527 Configuration Changes
in order to determine when the options to the code change, we need to mark the modification time of httpd.conf at request time, we call an API to compare the configuration modification to the If-Modified-Since header

528 Configuration Changes
in order to determine when the options to the code change, we need to mark the modification time of httpd.conf at request time, we call an API to compare the configuration modification to the If-Modified-Since header on restarts, we regenerate the configuration modification time

529 use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9];

530 use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; });

531 use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; });

532 use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; });

533 Resource Changes

534 Resource Changes in order to determine when the resources changes, we need to mark the modification time of $r->filename

535 Resource Changes in order to determine when the resources changes, we need to mark the modification time of $r->filename at request time, we call an API to compare the resource modification to the If-Modified-Since header

536 Resource Changes in order to determine when the resources changes, we need to mark the modification time of $r->filename at request time, we call an API to compare the resource modification to the If-Modified-Since header resource modification is checked on each request

537 use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; });

538 use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; }); sub handler { ... } 1;

539 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; }

540 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

541 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

542 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

543 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

544 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

545 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

546 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

547 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

548 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

549 my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;

550 Key Concepts

551 Key Concepts Apache::File

552 Key Concepts Apache::File update_mtime() and time comparisons

553 Key Concepts Apache::File update_mtime() and time comparisons
headers to never modify directly

554 Key Concepts Apache::File update_mtime() and time comparisons
headers to never modify directly meets_conditions() for header comparison

555 Apache::File

556 Apache::File when you use Apache::File; methods are added to the Apache class

557 Apache::File when you use Apache::File; methods are added to the Apache class update_mtime() set_content_length() set_last_modified() set_etag() meets_conditions() set_byterange() each_byterange()

558 update_mtime()

559 update_mtime() used to update the apparent modification time of the resource

560 update_mtime() used to update the apparent modification time of the resource compares the current resource mtime to the set attempt and keeps the most recent

561 update_mtime() used to update the apparent modification time of the resource compares the current resource mtime to the set attempt and keeps the most recent just pile calls to update_mtime() up and let Apache do the work

562 Special Headers

563 Special Headers some headers you don't want to manipulate with headers_out()

564 Special Headers some headers you don't want to manipulate with headers_out() Apache provides a special set of APIs for these

565 Special Headers some headers you don't want to manipulate with headers_out() Apache provides a special set of APIs for these the ones added by Apache::File

566 set_last_modified()

567 set_last_modified() sets the Last-Modified header

568 set_last_modified() sets the Last-Modified header
uses mtime slot in the request record by default

569 set_last_modified() sets the Last-Modified header
uses mtime slot in the request record by default can pass it a properly formatted time

570 set_etag()

571 set_etag() sets the ETag header

572 set_etag() sets the ETag header
ETag is supposed to be unique for every version of a resource that ever existed

573 set_etag() sets the ETag header
ETag is supposed to be unique for every version of a resource that ever existed use only with static resources

574 set_content_length()

575 set_content_length()
sets the Content-Length header

576 set_content_length()
sets the Content-Length header ...

577 meets_conditions()

578 meets_conditions() does all the nasty comparisons between the client and server headers

579 meets_conditions() does all the nasty comparisons between the client and server headers returns OK or HTTP_NOT_MODIFIED

580 meets_conditions() does all the nasty comparisons between the client and server headers returns OK or HTTP_NOT_MODIFIED sets the headers_out() as appropriate

581 meets_conditions() does all the nasty comparisons between the client and server headers returns OK or HTTP_NOT_MODIFIED sets the headers_out() as appropriate you need to set all your outgoing headers before calling meets_conditions()

582

583 Fine Manuals Writing Apache Modules with Perl and C
mod_perl Developer's Cookbook mod_perl Pocket Reference mod_perl Guide mod_perl at the ASF

584


Download ppt "Transitioning to mod_perl Handlers"

Similar presentations


Ads by Google