/usr/share/doc/libapache2-mod-perl2-doc/docs/2.0/user/handlers/http.html is in libapache2-mod-perl2-doc 2.0.8+httpd24-r1449661-6ubuntu2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 | <?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rev="made" href="mailto:root@localhost" />
</head>
<body style="background-color: white">
<ul id="index">
<li><a href="#NAME">NAME</a></li>
<li><a href="#Description">Description</a></li>
<li><a href="#HTTP-Request-Handler-Skeleton">HTTP Request Handler Skeleton</a></li>
<li><a href="#HTTP-Request-Cycle-Phases">HTTP Request Cycle Phases</a>
<ul>
<li><a href="#PerlPostReadRequestHandler">PerlPostReadRequestHandler</a></li>
<li><a href="#PerlTransHandler1">PerlTransHandler</a></li>
<li><a href="#PerlMapToStorageHandler1">PerlMapToStorageHandler</a></li>
<li><a href="#PerlHeaderParserHandler">PerlHeaderParserHandler</a></li>
<li><a href="#PerlInitHandler">PerlInitHandler</a></li>
<li><a href="#PerlAccessHandler1">PerlAccessHandler</a></li>
<li><a href="#PerlAuthenHandler1">PerlAuthenHandler</a></li>
<li><a href="#PerlAuthzHandler1">PerlAuthzHandler</a></li>
<li><a href="#PerlTypeHandler1">PerlTypeHandler</a></li>
<li><a href="#PerlFixupHandler1">PerlFixupHandler</a></li>
<li><a href="#PerlResponseHandler1">PerlResponseHandler</a></li>
<li><a href="#PerlLogHandler1">PerlLogHandler</a></li>
<li><a href="#PerlCleanupHandler1">PerlCleanupHandler</a>
<ul>
<li><a href="#Possible-Caveats">Possible Caveats</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#Miscellaneous-Issues">Miscellaneous Issues</a>
<ul>
<li><a href="#Handling-HEAD-Requests">Handling HEAD Requests</a></li>
<li><a href="#Content-Length-Response-Header">Content-Length Response Header</a></li>
</ul>
</li>
<li><a href="#Misc-Notes">Misc Notes</a></li>
<li><a href="#Extending-HTTP-Protocol">Extending HTTP Protocol</a></li>
<li><a href="#HTTP-Status-Codes">HTTP Status Codes</a>
<ul>
<li><a href="#HTTP-1.0-Status-Codes">HTTP 1.0 Status Codes</a></li>
<li><a href="#HTTP-1.1-Status-Codes">HTTP 1.1 Status Codes</a></li>
<li><a href="#References">References</a></li>
</ul>
</li>
<li><a href="#Maintainers">Maintainers</a></li>
<li><a href="#Authors">Authors</a></li>
</ul>
<h1 id="NAME">NAME</h1>
<p>HTTP Handlers</p>
<h1 id="Description">Description</h1>
<p>This chapter explains how to implement the HTTP protocol handlers in mod_perl.</p>
<h1 id="HTTP-Request-Handler-Skeleton">HTTP Request Handler Skeleton</h1>
<p>All HTTP Request handlers have the following structure:</p>
<pre><code> package MyApache2::MyHandlerName;
# load modules that are going to be used
use ...;
# compile (or import) constants
use Apache2::Const -compile => qw(OK);
sub handler {
my $r = shift;
# handler code comes here
return Apache2::Const::OK; # or another status constant
}
1;</code></pre>
<p>First, the package is declared. Next, the modules that are going to be used are loaded and constants compiled.</p>
<p>The handler itself coming next and usually it receives the only argument: the <code><a>Apache2::RequestRec</a></code> object. If the handler is declared as <a>a method handler </a>:</p>
<pre><code> sub handler : method {
my ($class, $r) = @_;</code></pre>
<p>the handler receives two arguments: the class name and the <code><a>Apache2::RequestRec</a></code> object.</p>
<p>The handler ends with <a>a return code</a> and the file is ended with <code>1;</code> to return true when it gets loaded.</p>
<h1 id="HTTP-Request-Cycle-Phases">HTTP Request Cycle Phases</h1>
<p>Those familiar with mod_perl 1.0 will find the HTTP request cycle in mod_perl 2.0 to be almost identical to the mod_perl 1.0's model. The different things are:</p>
<ul>
<li><p>a new directive <code><a href="#PerlMapToStorageHandler">PerlMapToStorageHandler</a></code> was added to match the new phase <i>map_to_storage</i> added by Apache 2.0.</p>
</li>
<li><p>the <code>PerlHandler</code> directive has been renamed to <code>PerlResponseHandler</code> to better match the corresponding Apache phase name (<i>response</i>).</p>
</li>
<li><p>the <i>response</i> phase now includes filtering.</p>
</li>
</ul>
<p>The following diagram depicts the HTTP request life cycle and highlights which handlers are available to mod_perl 2.0:</p>
<img src="http_cycle.gif" width="600" height="560"
align="middle" alt="HTTP cycle"><br><br>
<p>From the diagram it can be seen that an HTTP request is processed by 12 phases, executed in the following order:</p>
<dl>
<dt id="PerlPostReadRequestHandler-PerlInitHandler">1 PerlPostReadRequestHandler (PerlInitHandler)</dt>
<dd>
</dd>
<dt id="PerlTransHandler">2 PerlTransHandler</dt>
<dd>
</dd>
<dt id="PerlMapToStorageHandler">3 PerlMapToStorageHandler</dt>
<dd>
</dd>
<dt id="PerlHeaderParserHandler-PerlInitHandler">4 PerlHeaderParserHandler (PerlInitHandler)</dt>
<dd>
</dd>
<dt id="PerlAccessHandler">5 PerlAccessHandler</dt>
<dd>
</dd>
<dt id="PerlAuthenHandler">6 PerlAuthenHandler</dt>
<dd>
</dd>
<dt id="PerlAuthzHandler">7 PerlAuthzHandler</dt>
<dd>
</dd>
<dt id="PerlTypeHandler">8 PerlTypeHandler</dt>
<dd>
</dd>
<dt id="PerlFixupHandler">9 PerlFixupHandler</dt>
<dd>
</dd>
<dt id="PerlResponseHandler">10 PerlResponseHandler</dt>
<dd>
</dd>
<dt id="PerlLogHandler">11 PerlLogHandler</dt>
<dd>
</dd>
<dt id="PerlCleanupHandler">12 PerlCleanupHandler</dt>
<dd>
</dd>
</dl>
<p>It's possible that the cycle will not be completed if any of the phases terminates it, usually when an error happens. In that case Apache skips to the logging phase (mod_perl executes all registered <code>PerlLogHandler</code> handlers) and finally the cleanup phase happens.</p>
<p>Notice that when the response handler is reading the input data it can be filtered through request input filters, which are preceded by connection input filters if any. Similarly the generated response is first run through request output filters and eventually through connection output filters before it's sent to the client. We will talk about filters in detail later in <a>the dedicated to filters chapter</a>.</p>
<p>Before discussing each handler in detail remember that if you use <a>the stacked handlers feature</a> all handlers in the chain will be run as long as they return <code>Apache2::Const::OK</code> or <code>Apache2::Const::DECLINED</code>. Because stacked handlers is a special case. So don't be surprised if you've returned <code>Apache2::Const::OK</code> and the next handler was still executed. This is a feature, not a bug.</p>
<p>Now let's discuss each of the mentioned handlers in detail.</p>
<h2 id="PerlPostReadRequestHandler">PerlPostReadRequestHandler</h2>
<p>The <i>post_read_request</i> phase is the first request phase and happens immediately after the request has been read and HTTP headers were parsed.</p>
<p>This phase is usually used to do processing that must happen once per request. For example <code>Apache2::Reload</code> is usually invoked at this phase to reload modified Perl modules.</p>
<p>This phase is of type <code><a>RUN_ALL</a></code>.</p>
<p>The handler's configuration scope is <code><a>SRV</a></code>, because at this phase the request has not yet been associated with a particular filename or directory.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>Now, let's look at an example. Consider the following registry script:</p>
<pre><code> #file:touch.pl
#-------------
use strict;
use warnings;
use Apache2::ServerUtil ();
use Apache2::RequestIO ();
use File::Spec::Functions qw(catfile);
my $r = shift;
$r->content_type('text/plain');
my $conf_file = catfile Apache2::ServerUtil::server_root,
"conf", "httpd.conf";
printf "$conf_file is %0.2f minutes old\n", 60*24*(-M $conf_file);</code></pre>
<p>This registry script is supposed to print when the last time <i>httpd.conf</i> has been modified, compared to the start of the request process time. If you run this script several times you might be surprised that it reports the same value all the time. Unless the request happens to be served by a recently started child process which will then report a different value. But most of the time the value won't be reported correctly.</p>
<p>This happens because the <code>-M</code> operator reports the difference between file's modification time and the value of a special Perl variable <code>$^T</code>. When we run scripts from the command line, this variable is always set to the time when the script gets invoked. Under mod_perl this variable is getting preset once when the child process starts and doesn't change since then, so all requests see the same time, when operators like <code>-M</code>, <code>-C</code> and <code>-A</code> are used.</p>
<p>Armed with this knowledge, in order to make our code behave similarly to the command line programs we need to reset <code>$^T</code> to the request's start time, before <code>-M</code> is used. We can change the script itself, but what if we need to do the same change for several other scripts and handlers? A simple <code>PerlPostReadRequestHandler</code> handler, which will be executed as the very first thing of each requests, comes handy here:</p>
<pre><code> #file:MyApache2/TimeReset.pm
#--------------------------
package MyApache2::TimeReset;
use strict;
use warnings;
use Apache2::RequestRec ();
use Apache2::Const -compile => 'OK';
sub handler {
my $r = shift;
$^T = $r->request_time;
return Apache2::Const::OK;
}
1;</code></pre>
<p>We could do:</p>
<pre><code> $^T = time();</code></pre>
<p>But to make things more efficient we use <code>$r->request_time</code> since the request object <code>$r</code> already stores the request's start time, so we get it without performing an additional system call.</p>
<p>To enable it just add to <i>httpd.conf</i>:</p>
<pre><code> PerlPostReadRequestHandler MyApache2::TimeReset</code></pre>
<p>either to the global section, or to the <code><VirtualHost></code> section if you want this handler to be run only for a specific virtual host.</p>
<h2 id="PerlTransHandler1">PerlTransHandler</h2>
<p>The <i>translate</i> phase is used to perform the manipulation of a request's URI. If no custom handler is provided, the server's standard translation rules (e.g., <code>Alias</code> directives, mod_rewrite, etc.) will be used. A <code>PerlTransHandler</code> handler can alter the default translation mechanism or completely override it. This is also a good place to register new handlers for the following phases based on the URI. <code><a href="#PerlMapToStorageHandler">PerlMapToStorageHandler</a></code> is to be used to override the URI to filename translation.</p>
<p>This phase is of type <code><a>RUN_FIRST</a></code>.</p>
<p>The handler's configuration scope is <code><a>SRV</a></code>, because at this phase the request has not yet been associated with a particular filename or directory.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>There are many useful things that can be performed at this stage. Let's look at the example handler that rewrites request URIs, similar to what mod_rewrite does. For example, if your web-site was originally made of static pages, and now you have moved to a dynamic page generation chances are that you don't want to change the old URIs, because you don't want to break links for those who link to your site. If the URI:</p>
<pre><code> http://example.com/news/20021031/09/index.html</code></pre>
<p>is now handled by:</p>
<pre><code> http://example.com/perl/news.pl?date=20021031;id=09;page=index.html</code></pre>
<p>the following handler can do the rewriting work transparent to <i>news.pl</i>, so you can still use the former URI mapping:</p>
<pre><code> #file:MyApache2/RewriteURI.pm
#---------------------------
package MyApache2::RewriteURI;
use strict;
use warnings;
use Apache2::RequestRec ();
use Apache2::Const -compile => qw(DECLINED);
sub handler {
my $r = shift;
my ($date, $id, $page) = $r->uri =~ m|^/news/(\d+)/(\d+)/(.*)|;
$r->uri("/perl/news.pl");
$r->args("date=$date;id=$id;page=$page");
return Apache2::Const::DECLINED;
}
1;</code></pre>
<p>The handler matches the URI and assigns a new URI via <code>$r->uri()</code> and the query string via <code>$r->args()</code>. It then returns <code>Apache2::Const::DECLINED</code>, so the next translation handler will get invoked, if more rewrites and translations are needed.</p>
<p>Of course if you need to do a more complicated rewriting, this handler can be easily adjusted to do so.</p>
<p>To configure this module simply add to <i>httpd.conf</i>:</p>
<pre><code> PerlTransHandler +MyApache2::RewriteURI</code></pre>
<h2 id="PerlMapToStorageHandler1">PerlMapToStorageHandler</h2>
<p>The <i>map_to_storage</i> phase is used to perform the translation of a request's URI into a corresponding filename. If no custom handler is provided, the server will try to walk the filesystem trying to find what file or directory corresponds to the request's URI. Since usually mod_perl handler don't have corresponding files on the filesystem, you will want to shortcut this phase and save quite a few CPU cycles.</p>
<p>This phase is of type <code><a>RUN_FIRST</a></code>.</p>
<p>The handler's configuration scope is <code><a>SRV</a></code>, because at this phase the request has not yet been associated with a particular filename or directory.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>For example if you don't want Apache to try to attempt to translate URI into a filename, just add a handler:</p>
<pre><code> PerlMapToStorageHandler MyApache2::NoTranslation</code></pre>
<p>using the following code:</p>
<pre><code> #file:MyApache2/NoTranslation.pm
#------------------------------
package MyApache2::NoTranslation;
use strict;
use warnings FATAL => 'all';
use Apache2::Const -compile => qw(OK);
sub handler {
my $r = shift;
# skip ap_directory_walk stat() calls
return Apache2::Const::OK;
}
1;</code></pre>
<p>But this can be done from <i>httpd.conf</i> too!</p>
<pre><code> PerlMapToStorageHandler Apache2::Const::OK</code></pre>
<p>If you haven't already compiled <code>Apache2::Const::OK</code> elsewhere, you should add:</p>
<pre><code> <Perl>
use Apache2::Const -compile => qw(OK);
</Perl></code></pre>
<p>Apache also uses this phase to handle <code>TRACE</code> requests. So if you shortcut it, <code>TRACE</code> calls will be not handled. In case you need to handle such, you may rewrite it as:</p>
<pre><code> #file:MyApache2/NoTranslation2.pm
#-------------------------------
package MyApache2::NoTranslation2;
use strict;
use warnings FATAL => 'all';
use Apache2::RequestRec ();
use Apache2::Const -compile => qw(DECLINED OK M_TRACE);
sub handler {
my $r = shift;
return Apache2::Const::DECLINED
if $r->method_number == Apache2::Const::M_TRACE;
# skip ap_directory_walk stat() calls
return Apache2::Const::OK;
}
1;</code></pre>
<p>BTW, the HTTP TRACE method asks a web server to echo the contents of the request back to the client for debugging purposes. i.e., the complete request, including HTTP headers, is returned in the entity-body of a TRACE response. Attackers may abuse HTTP TRACE functionality to gain access to information in HTTP headers such as cookies and authentication data. In the presence of other cross-domain vulnerabilities in web browsers, sensitive header information could be read from any domains that support the HTTP TRACE method.</p>
<p>Another way to prevent the core translation is to set <code>$r->filename()</code> to some value, which can also be done in the <code><a href="#PerlTransHandler">PerlTransHandler</a></code>, if you are already using it.</p>
<h2 id="PerlHeaderParserHandler">PerlHeaderParserHandler</h2>
<p>The <i>header_parser</i> phase is the first phase to happen after the request has been mapped to its <code><Location></code> (or an equivalent container). At this phase the handler can examine the request headers and to take a special action based on these. For example this phase can be used to block evil clients targeting certain resources, while little resources were wasted so far.</p>
<p>This phase is of type <code><a>RUN_ALL</a></code>.</p>
<p>The handler's configuration scope is <code><a>DIR</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>This phase is very similar to <code><a href="#PerlPostReadRequestHandler">PerlPostReadRequestHandler</a></code>, with the only difference that it's run after the request has been mapped to the resource. Both phases are useful for doing something once per request, as early as possible. And usually you can take any <code><a href="#PerlPostReadRequestHandler">PerlPostReadRequestHandler</a></code> and turn it into <code><a href="#PerlHeaderParserHandler">PerlHeaderParserHandler</a></code> by simply changing the directive name in <i>httpd.conf</i> and moving it inside the container where it should be executed. Moreover, because of this similarity mod_perl provides a special directive <code><a href="#PerlInitHandler">PerlInitHandler</a></code> which if found outside resource containers behaves as <code><a href="#PerlPostReadRequestHandler">PerlPostReadRequestHandler</a></code>, otherwise as <code><a href="#PerlHeaderParserHandler">PerlHeaderParserHandler</a></code>.</p>
<p>You already know that Apache handles the <code>HEAD</code>, <code>GET</code>, <code>POST</code> and several other HTTP methods. But did you know that you can invent your own HTTP method as long as there is a client that supports it. If you think of emails, they are very similar to HTTP messages: they have a set of headers and a body, sometimes a multi-part body. Therefore we can develop a handler that extends HTTP by adding a support for the <code>EMAIL</code> method. We can enable this protocol extension and push the real content handler during the <code><a href="#PerlHeaderParserHandler">PerlHeaderParserHandler</a></code> phase:</p>
<pre><code> <Location /email>
PerlHeaderParserHandler MyApache2::SendEmail
</Location></code></pre>
<p>and here is the <code>MyApache2::SendEmail</code> handler:</p>
<pre><code> #file:MyApache2/SendEmail.pm
#--------------------------
package MyApache2::SendEmail;
use strict;
use warnings;
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::RequestUtil ();
use Apache2::ServerUtil ();
use Apache2::ServerRec ();
use Apache2::Process ();
use APR::Table ();
use Apache2::Const -compile => qw(DECLINED OK);
use constant METHOD => 'EMAIL';
use constant SMTP_HOSTNAME => "localhost";
sub handler {
my $r = shift;
return Apache2::Const::DECLINED unless $r->method eq METHOD;
$r->server->method_register(METHOD);
$r->handler("perl-script");
$r->push_handlers(PerlResponseHandler => \&send_email_handler);
return Apache2::Const::OK;
}
sub send_email_handler {
my $r = shift;
my %headers = map {$_ => $r->headers_in->get($_)}
qw(To From Subject);
my $content = content($r);
my $status = send_email(\%headers, \$content);
$r->content_type('text/plain');
$r->print($status ? "ACK" : "NACK");
return Apache2::Const::OK;
}
sub send_email {
my ($rh_headers, $r_body) = @_;
require MIME::Lite;
MIME::Lite->send("smtp", SMTP_HOSTNAME, Timeout => 60);
my $msg = MIME::Lite->new(%$rh_headers, Data => $$r_body);
#warn $msg->as_string;
$msg->send;
}
use APR::Brigade ();
use APR::Bucket ();
use Apache2::Const -compile => qw(MODE_READBYTES);
use APR::Const -compile => qw(SUCCESS BLOCK_READ);
use constant IOBUFSIZE => 8192;
sub content {
my $r = shift;
my $bb = APR::Brigade->new($r->pool, $r->connection->bucket_alloc);
my $data = '';
my $seen_eos = 0;
do {
$r->input_filters->get_brigade($bb,
Apache2::Const::MODE_READBYTES,
APR::Const::BLOCK_READ, IOBUFSIZE);
for (my $b = $bb->first; $b; $b = $bb->next($b)) {
if ($b->is_eos) {
$seen_eos++;
last;
}
if ($b->read(my $buf)) {
$data .= $buf;
}
$b->remove; # optimization to reuse memory
}
} while (!$seen_eos);
$bb->destroy;
return $data;
}
1;</code></pre>
<p>Let's get the less interesting code out of the way. The function content() grabs the request body. The function send_email() sends the email over SMTP. You should adjust the constant <code>SMTP_HOSTNAME</code> to point to your outgoing SMTP server. You can replace this function with your own if you prefer to use a different method to send email.</p>
<p>Now to the more interesting functions. The function <code>handler()</code> returns immediately and passes the control to the next handler if the request method is not equal to <code>EMAIL</code> (set in the <code>METHOD</code> constant):</p>
<pre><code> return Apache2::Const::DECLINED unless $r->method eq METHOD;</code></pre>
<p>Next it tells Apache that this new method is a valid one and that the <code>perl-script</code> handler will do the processing.</p>
<pre><code> $r->server->method_register(METHOD);
$r->handler("perl-script");</code></pre>
<p>Finally it pushes the function <code>send_email_handler()</code> to the <code>PerlResponseHandler</code> list of handlers:</p>
<pre><code> $r->push_handlers(PerlResponseHandler => \&send_email_handler);</code></pre>
<p>The function terminates the header_parser phase by:</p>
<pre><code> return Apache2::Const::OK;</code></pre>
<p>All other phases run as usual, so you can reuse any HTTP protocol hooks, such as authentication and fixup phases.</p>
<p>When the response phase starts <code>send_email_handler()</code> is invoked, assuming that no other response handlers were inserted before it. The response handler consists of three parts. Retrieve the email headers <code>To</code>, <code>From</code> and <code>Subject</code>, and the body of the message:</p>
<pre><code> my %headers = map {$_ => $r->headers_in->get($_)}
qw(To From Subject);
my $content = $r->content;</code></pre>
<p>Then send the email:</p>
<pre><code> my $status = send_email(\%headers, \$content);</code></pre>
<p>Finally return to the client a simple response acknowledging that email has been sent and finish the response phase by returning <code>Apache2::Const::OK</code>:</p>
<pre><code> $r->content_type('text/plain');
$r->print($status ? "ACK" : "NACK");
return Apache2::Const::OK;</code></pre>
<p>Of course you will want to add extra validations if you want to use this code in production. This is just a proof of concept implementation.</p>
<p>As already mentioned when you extend an HTTP protocol you need to have a client that knows how to use the extension. So here is a simple client that uses <code>LWP::UserAgent</code> to issue an <code>EMAIL</code> method request over HTTP protocol:</p>
<pre><code> #file:send_http_email.pl
#-----------------------
#!/usr/bin/perl
use strict;
use warnings;
require LWP::UserAgent;
my $url = "http://localhost:8000/email/";
my %headers = (
From => 'example@example.com',
To => 'example@example.com',
Subject => '3 weeks in Tibet',
);
my $content = <<EOI;
I didn't have an email software,
but could use HTTP so I'm sending it over HTTP
EOI
my $headers = HTTP::Headers->new(%headers);
my $req = HTTP::Request->new("EMAIL", $url, $headers, $content);
my $res = LWP::UserAgent->new->request($req);
print $res->is_success ? $res->content : "failed";</code></pre>
<p>most of the code is just a custom data. The code that does something consists of four lines at the very end. Create <code>HTTP::Headers</code> and <code>HTTP::Request</code> object. Issue the request and get the response. Finally print the response's content if it was successful or just <i>"failed"</i> if not.</p>
<p>Now save the client code in the file <i>send_http_email.pl</i>, adjust the <i>To</i> field, make the file executable and execute it, after you have restarted the server. You should receive an email shortly to the address set in the <i>To</i> field.</p>
<h2 id="PerlInitHandler">PerlInitHandler</h2>
<p>When configured inside any container directive, except <code><VirtualHost></code>, this handler is an alias for <code><a href="#PerlHeaderParserHandler">PerlHeaderParserHandler</a></code> described earlier. Otherwise it acts as an alias for <code><a href="#PerlPostReadRequestHandler">PerlPostReadRequestHandler</a></code> described earlier.</p>
<p>It is the first handler to be invoked when serving a request.</p>
<p>This phase is of type <code><a>RUN_ALL</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>The best example here would be to use <code><a>Apache2::Reload</a></code> which takes the benefit of this directive. Usually <code><a>Apache2::Reload</a></code> is configured as:</p>
<pre><code> PerlInitHandler Apache2::Reload
PerlSetVar ReloadAll Off
PerlSetVar ReloadModules "MyApache2::*"</code></pre>
<p>which during the current HTTP request will monitor and reload all <code>MyApache2::*</code> modules that have been modified since the last HTTP request. However if we move the global configuration into a <code><Location></code> container:</p>
<pre><code> <Location /devel>
PerlInitHandler Apache2::Reload
PerlSetVar ReloadAll Off
PerlSetVar ReloadModules "MyApache2::*"
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
Options +ExecCGI
</Location></code></pre>
<p><code><a>Apache2::Reload</a></code> will reload the modified modules, only when a request to the <i>/devel</i> namespace is issued, because <code><a href="#PerlInitHandler">PerlInitHandler</a></code> plays the role of <code><a href="#PerlHeaderParserHandler">PerlHeaderParserHandler</a></code> here.</p>
<h2 id="PerlAccessHandler1">PerlAccessHandler</h2>
<p>The <i>access_checker</i> phase is the first of three handlers that are involved in what's known as AAA: Authentication, Authorization, and Access control.</p>
<p>This phase can be used to restrict access from a certain IP address, time of the day or any other rule not connected to the user's identity.</p>
<p>This phase is of type <code><a>RUN_ALL</a></code>.</p>
<p>The handler's configuration scope is <code><a>DIR</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>The concept behind access checker handler is very simple, return <code>Apache2::Const::FORBIDDEN</code> if the access is not allowed, otherwise return <code>Apache2::Const::OK</code>.</p>
<p>The following example handler denies requests made from IPs on the blacklist.</p>
<pre><code> #file:MyApache2/BlockByIP.pm
#--------------------------
package MyApache2::BlockByIP;
use strict;
use warnings;
use Apache2::RequestRec ();
use Apache2::Connection ();
use Apache2::Const -compile => qw(FORBIDDEN OK);
my %bad_ips = map {$_ => 1} qw(127.0.0.1 10.0.0.4);
sub handler {
my $r = shift;
return exists $bad_ips{$r->connection->remote_ip}
? Apache2::Const::FORBIDDEN
: Apache2::Const::OK;
}
1;</code></pre>
<p>The handler retrieves the connection's IP address, looks it up in the hash of blacklisted IPs and forbids the access if found. If the IP is not blacklisted, the handler returns control to the next access checker handler, which may still block the access based on a different rule.</p>
<p>To enable the handler simply add it to the container that needs to be protected. For example to protect an access to the registry scripts executed from the base location <i>/perl</i> add:</p>
<pre><code> <Location /perl/>
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlAccessHandler MyApache2::BlockByIP
Options +ExecCGI
</Location></code></pre>
<p>It's important to notice that <code>PerlAccessHandler</code> can be configured for any subsection of the site, no matter whether it's served by a mod_perl response handler or not. For example to run the handler from our example for all requests to the server simply add to <i>httpd.conf</i>:</p>
<pre><code> <Location />
PerlAccessHandler MyApache2::BlockByIP
</Location></code></pre>
<h2 id="PerlAuthenHandler1">PerlAuthenHandler</h2>
<p>The <i>check_user_id</i> (<i>authen</i>) phase is called whenever the requested file or directory is password protected. This, in turn, requires that the directory be associated with <code>AuthName</code>, <code>AuthType</code> and at least one <code>require</code> directive.</p>
<p>This phase is usually used to verify a user's identification credentials. If the credentials are verified to be correct, the handler should return <code>Apache2::Const::OK</code>. Otherwise the handler returns <code>Apache2::Const::HTTP_UNAUTHORIZED</code> to indicate that the user has not authenticated successfully. When Apache sends the HTTP header with this code, the browser will normally pop up a dialog box that prompts the user for login information.</p>
<p>This phase is of type <code><a>RUN_FIRST</a></code>.</p>
<p>The handler's configuration scope is <code><a>DIR</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>The following handler authenticates users by asking for a username and a password and lets them in only if the length of a string made from the supplied username and password and a single space equals to the secret length, specified by the constant <code>SECRET_LENGTH</code>.</p>
<pre><code> #file:MyApache2/SecretLengthAuth.pm
#---------------------------------
package MyApache2::SecretLengthAuth;
use strict;
use warnings;
use Apache2::Access ();
use Apache2::RequestUtil ();
use Apache2::Const -compile => qw(OK DECLINED HTTP_UNAUTHORIZED);
use constant SECRET_LENGTH => 14;
sub handler {
my $r = shift;
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == Apache2::Const::OK;
return Apache2::Const::OK
if SECRET_LENGTH == length join " ", $r->user, $password;
$r->note_basic_auth_failure;
return Apache2::Const::HTTP_UNAUTHORIZED;
}
1;</code></pre>
<p>First the handler retrieves the status of the authentication and the password in plain text. The status will be set to <code>Apache2::Const::OK</code> only when the user has supplied the username and the password credentials. If the status is different, we just let Apache handle this situation for us, which will usually challenge the client so it'll supply the credentials.</p>
<p>Note that <code>get_basic_auth_pw()</code> does a few things behind the scenes, which are important to understand if you plan on implementing your own authentication mechanism that does not use <code>get_basic_auth_pw()</code>. First, is checks the value of the configured <code>AuthType</code> for the request, making sure it is <code>Basic</code>. Then it makes sure that the Authorization (or Proxy-Authorization) header is formatted for <code>Basic</code> authentication. Finally, after isolating the user and password from the header, it populates the <i>ap_auth_type</i> slot in the request record with <code>Basic</code>. For the first and last parts of this process, mod_perl offers an API. <code>$r->auth_type</code> returns the configured authentication type for the current request - whatever was set via the <code>AuthType</code> configuration directive. <code>$r->ap_auth_type</code> populates the <i>ap_auth_type</i> slot in the request record, which should be done after it has been confirmed that the request is indeed using <code>Basic</code> authentication. (Note: <code>$r->ap_auth_type</code> was <code>$r->connection->auth_type</code> in the mod_perl 1.0 API.)</p>
<p>Once we know that we have the username and the password supplied by the client, we can proceed with the authentication. Our authentication algorithm is unusual. Instead of validating the username/password pair against a password file, we simply check that the string built from these two items plus a single space is <code>SECRET_LENGTH</code> long (14 in our example). So for example the pair <i>mod_perl/rules</i> authenticates correctly, whereas <i>secret/password</i> does not, because the latter pair will make a string of 15 characters. Of course this is not a strong authentication scheme and you shouldn't use it for serious things, but it's fun to play with. Most authentication validations simply verify the username/password against a database of valid pairs, usually this requires the password to be encrypted first, since storing passwords in clear is a bad idea.</p>
<p>Finally if our authentication fails the handler calls note_basic_auth_failure() and returns <code>Apache2::Const::HTTP_UNAUTHORIZED</code>, which sets the proper HTTP response headers that tell the client that its user that the authentication has failed and the credentials should be supplied again.</p>
<p>It's not enough to enable this handler for the authentication to work. You have to tell Apache what authentication scheme to use (<code>Basic</code> or <code>Digest</code>), which is specified by the <code>AuthType</code> directive, and you should also supply the <code>AuthName</code> -- the authentication realm, which is really just a string that the client usually uses as a title in the pop-up box, where the username and the password are inserted. Finally the <code>Require</code> directive is needed to specify which usernames are allowed to authenticate. If you set it to <code>valid-user</code> any username will do.</p>
<p>Here is the whole configuration section that requires users to authenticate before they are allowed to run the registry scripts from <i>/perl/</i>:</p>
<pre><code> <Location /perl/>
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlAuthenHandler MyApache2::SecretLengthAuth
Options +ExecCGI
AuthType Basic
AuthName "The Gate"
Require valid-user
</Location></code></pre>
<p>Just like <code>PerlAccessHandler</code> and other mod_perl handlers, <code>PerlAuthenHandler</code> can be configured for any subsection of the site, no matter whether it's served by a mod_perl response handler or not. For example to use the authentication handler from the last example for any requests to the site, simply use:</p>
<pre><code> <Location />
PerlAuthenHandler MyApache2::SecretLengthAuth
AuthType Basic
AuthName "The Gate"
Require valid-user
</Location></code></pre>
<h2 id="PerlAuthzHandler1">PerlAuthzHandler</h2>
<p>The <i>auth_checker</i> (<i>authz</i>) phase is used for authorization control. This phase requires a successful authentication from the previous phase, because a username is needed in order to decide whether a user is authorized to access the requested resource.</p>
<p>As this phase is tightly connected to the authentication phase, the handlers registered for this phase are only called when the requested resource is password protected, similar to the auth phase. The handler is expected to return <code>Apache2::Const::DECLINED</code> to defer the decision, <code>Apache2::Const::OK</code> to indicate its acceptance of the user's authorization, or <code>Apache2::Const::HTTP_UNAUTHORIZED</code> to indicate that the user is not authorized to access the requested document.</p>
<p>This phase is of type <code><a>RUN_FIRST</a></code>.</p>
<p>The handler's configuration scope is <code><a>DIR</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>Here is the <code>MyApache2::SecretResourceAuthz</code> handler which grants access to certain resources only to certain users who have already properly authenticated:</p>
<pre><code> #file:MyApache2/SecretResourceAuthz.pm
#------------------------------------
package MyApache2::SecretResourceAuthz;
use strict;
use warnings;
use Apache2::Access ();
use Apache2::RequestUtil ();
use Apache2::Const -compile => qw(OK HTTP_UNAUTHORIZED);
my %protected = (
'admin' => ['stas'],
'report' => [qw(stas boss)],
);
sub handler {
my $r = shift;
my $user = $r->user;
if ($user) {
my ($section) = $r->uri =~ m|^/company/(\w+)/|;
if (defined $section && exists $protected{$section}) {
my $users = $protected{$section};
return Apache2::Const::OK if grep { $_ eq $user } @$users;
}
else {
return Apache2::Const::OK;
}
}
$r->note_basic_auth_failure;
return Apache2::Const::HTTP_UNAUTHORIZED;
}
1;</code></pre>
<p>This authorization handler is very similar to the authentication handler <a href="#PerlAuthenHandler">from the previous section</a>. Here we rely on the previous phase to get users authenticated, and now as we have the username we can make decisions whether to let the user access the resource it has asked for or not. In our example we have a simple hash which maps which users are allowed to access what resources. So for example anything under <i>/company/admin/</i> can be accessed only by the user <i>stas</i>, <i>/company/report/</i> can be accessed by users <i>stas</i> and <i>boss</i>, whereas any other resources under <i>/company/</i> can be accessed by everybody who has reached so far. If for some reason we don't get the username, we or the user is not authorized to access the resource the handler does the same thing as it does when the authentication fails, i.e, calls:</p>
<pre><code> $r->note_basic_auth_failure;
return Apache2::Const::HTTP_UNAUTHORIZED;</code></pre>
<p>The configuration is similar to the one in <a href="#PerlAuthenHandler">the previous section</a>, this time we just add the <code>PerlAuthzHandler</code> setting. The rest doesn't change.</p>
<pre><code> Alias /company/ /home/httpd/httpd-2.0/perl/
<Location /company/>
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlAuthenHandler MyApache2::SecretLengthAuth
PerlAuthzHandler MyApache2::SecretResourceAuthz
Options +ExecCGI
AuthType Basic
AuthName "The Secret Gate"
Require valid-user
</Location></code></pre>
<p>And if you want to run the authentication and authorization for the whole site, simply add:</p>
<pre><code> <Location />
PerlAuthenHandler MyApache2::SecretLengthAuth
PerlAuthzHandler MyApache2::SecretResourceAuthz
AuthType Basic
AuthName "The Secret Gate"
Require valid-user
</Location></code></pre>
<h2 id="PerlTypeHandler1">PerlTypeHandler</h2>
<p>The <i>type_checker</i> phase is used to set the response MIME type (<code>Content-type</code>) and sometimes other bits of document type information like the document language.</p>
<p>For example <code>mod_autoindex</code>, which performs automatic directory indexing, uses this phase to map the filename extensions to the corresponding icons which will be later used in the listing of files.</p>
<p>Of course later phases may override the mime type set in this phase.</p>
<p>This phase is of type <code><a>RUN_FIRST</a></code>.</p>
<p>The handler's configuration scope is <code><a>DIR</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>The most important thing to remember when overriding the default <i>type_checker</i> handler, which is usually the mod_mime handler, is that you have to set the handler that will take care of the response phase and the response callback function or the code won't work. mod_mime does that based on <code>SetHandler</code> and <code>AddHandler</code> directives, and file extensions. So if you want the content handler to be run by mod_perl, set either:</p>
<pre><code> $r->handler('perl-script');
$r->set_handlers(PerlResponseHandler => \&handler);</code></pre>
<p>or:</p>
<pre><code> $r->handler('modperl');
$r->set_handlers(PerlResponseHandler => \&handler);</code></pre>
<p>depending on which type of response handler is wanted.</p>
<p>Writing a <code>PerlTypeHandler</code> handler which sets the content-type value and returns <code>Apache2::Const::DECLINED</code> so that the default handler will do the rest of the work, is not a good idea, because mod_mime will probably override this and other settings.</p>
<p>Therefore it's the easiest to leave this stage alone and do any desired settings in the <i>fixups</i> phase.</p>
<h2 id="PerlFixupHandler1">PerlFixupHandler</h2>
<p>The <i>fixups</i> phase is happening just before the content handling phase. It gives the last chance to do things before the response is generated. For example in this phase <code>mod_env</code> populates the environment with variables configured with <i>SetEnv</i> and <i>PassEnv</i> directives.</p>
<p>This phase is of type <code><a>RUN_ALL</a></code>.</p>
<p>The handler's configuration scope is <code><a>DIR</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>The following fixup handler example tells Apache at run time which handler and callback should be used to process the request based on the file extension of the request's URI.</p>
<pre><code> #file:MyApache2/FileExtDispatch.pm
#--------------------------------
package MyApache2::FileExtDispatch;
use strict;
use warnings;
use Apache2::RequestIO ();
use Apache2::RequestRec ();
use Apache2::RequestUtil ();
use Apache2::Const -compile => 'OK';
use constant HANDLER => 0;
use constant CALLBACK => 1;
my %exts = (
cgi => ['perl-script', \&cgi_handler],
pl => ['modperl', \&pl_handler ],
tt => ['perl-script', \&tt_handler ],
txt => ['default-handler', undef ],
);
sub handler {
my $r = shift;
my ($ext) = $r->uri =~ /\.(\w+)$/;
$ext = 'txt' unless defined $ext and exists $exts{$ext};
$r->handler($exts{$ext}->[HANDLER]);
if (defined $exts{$ext}->[CALLBACK]) {
$r->set_handlers(PerlResponseHandler => $exts{$ext}->[CALLBACK]);
}
return Apache2::Const::OK;
}
sub cgi_handler { content_handler($_[0], 'cgi') }
sub pl_handler { content_handler($_[0], 'pl') }
sub tt_handler { content_handler($_[0], 'tt') }
sub content_handler {
my ($r, $type) = @_;
$r->content_type('text/plain');
$r->print("A handler of type '$type' was called");
return Apache2::Const::OK;
}
1;</code></pre>
<p>In the example we have used the following mapping.</p>
<pre><code> my %exts = (
cgi => ['perl-script', \&cgi_handler],
pl => ['modperl', \&pl_handler ],
tt => ['perl-script', \&tt_handler ],
txt => ['default-handler', undef ],
);</code></pre>
<p>So that <i>.cgi</i> requests will be handled by the <code>perl-script</code> handler and the <code>cgi_handler()</code> callback, <i>.pl</i> requests by <code>modperl</code> and <code>pl_handler()</code>, <i>.tt</i> (template toolkit) by <code>perl-script</code> and the <code>tt_handler()</code>, finally <i>.txt</i> request by the <code>default-handler</code> handler, which requires no callback.</p>
<p>Moreover the handler assumes that if the request's URI has no file extension or it does, but it's not in its mapping, the <code>default-handler</code> will be used, as if the <i>txt</i> extension was used.</p>
<p>After doing the mapping, the handler assigns the handler:</p>
<pre><code> $r->handler($exts{$ext}->[HANDLER]);</code></pre>
<p>and the callback if needed:</p>
<pre><code> if (defined $exts{$ext}->[CALLBACK]) {
$r->set_handlers(
PerlResponseHandler => $exts{$ext}->[CALLBACK]);
}</code></pre>
<p>In this simple example the callback functions don't do much but calling the same content handler which simply prints the name of the extension if handled by mod_perl, otherwise Apache will serve the other files using the default handler. In real world you will use callbacks to real content handlers that do real things.</p>
<p>Here is how this handler is configured:</p>
<pre><code> Alias /dispatch/ /home/httpd/httpd-2.0/htdocs/
<Location /dispatch/>
PerlFixupHandler MyApache2::FileExtDispatch
</Location></code></pre>
<p>Notice that there is no need to specify anything, but the fixup handler. It applies the rest of the settings dynamically at run-time.</p>
<h2 id="PerlResponseHandler1">PerlResponseHandler</h2>
<p>The <i>handler</i> (<i>response</i>) phase is used for generating the response. This is arguably the most important phase and most of the existing Apache modules do most of their work at this phase.</p>
<p>This is the only phase that requires two directives under mod_perl. For example:</p>
<pre><code> <Location /perl>
SetHandler perl-script
PerlResponseHandler MyApache2::WorldDomination
</Location></code></pre>
<p><code>SetHandler</code> set to <code><a>perl-script</a></code> or <code><a>modperl</a></code> tells Apache that mod_perl is going to handle the response generation. <code>PerlResponseHandler</code> tells mod_perl which callback is going to do the job.</p>
<p>This phase is of type <code><a>RUN_FIRST</a></code>.</p>
<p>The handler's configuration scope is <code><a>DIR</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>Most of the <code>Apache::</code> modules on CPAN are dealing with this phase. In fact most of the developers spend the majority of their time working on handlers that generate response content.</p>
<p>Let's write a simple response handler, that just generates some content. This time let's do something more interesting than printing <i>"Hello world"</i>. Let's write a handler that prints itself:</p>
<pre><code> #file:MyApache2/Deparse.pm
#------------------------
package MyApache2::Deparse;
use strict;
use warnings;
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use B::Deparse ();
use Apache2::Const -compile => 'OK';
sub handler {
my $r = shift;
$r->content_type('text/plain');
$r->print('sub handler ', B::Deparse->new->coderef2text(\&handler));
return Apache2::Const::OK;
}
1;</code></pre>
<p>To enable this handler add to <i>httpd.conf</i>:</p>
<pre><code> <Location /deparse>
SetHandler modperl
PerlResponseHandler MyApache2::Deparse
</Location></code></pre>
<p>Now when the server is restarted and we issue a request to <i>http://localhost/deparse</i> we get the following response:</p>
<pre><code> sub handler {
package MyApache2::Deparse;
use warnings;
use strict 'refs';
my $r = shift @_;
$r->content_type('text/plain');
$r->print('sub handler ', 'B::Deparse'->new->coderef2text(\&handler));
return 0;
}</code></pre>
<p>If you compare it to the source code, it's pretty much the same code. <code>B::Deparse</code> is fun to play with!</p>
<h2 id="PerlLogHandler1">PerlLogHandler</h2>
<p>The <i>log_transaction</i> phase happens no matter how the previous phases have ended up. If one of the earlier phases has aborted a request, e.g., failed authentication or 404 (file not found) errors, the rest of the phases up to and including the response phases are skipped. But this phase is always executed.</p>
<p>By this phase all the information about the request and the response is known, therefore the logging handlers usually record this information in various ways (e.g., logging to a flat file or a database).</p>
<p>This phase is of type <code><a>RUN_ALL</a></code>.</p>
<p>The handler's configuration scope is <code><a>DIR</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>Imagine a situation where you have to log requests into individual files, one per user. Assuming that all requests start with <i>/~username/</i>, so it's easy to categorize requests by the username. Here is the log handler that does that:</p>
<pre><code> #file:MyApache2/LogPerUser.pm
#---------------------------
package MyApache2::LogPerUser;
use strict;
use warnings;
use Apache2::RequestRec ();
use Apache2::Connection ();
use Fcntl qw(:flock);
use File::Spec::Functions qw(catfile);
use Apache2::Const -compile => qw(OK DECLINED);
sub handler {
my $r = shift;
my ($username) = $r->uri =~ m|^/~([^/]+)|;
return Apache2::Const::DECLINED unless defined $username;
my $entry = sprintf qq(%s [%s] "%s" %d %d\n),
$r->connection->remote_ip, scalar(localtime),
$r->uri, $r->status, $r->bytes_sent;
my $log_path = catfile Apache2::ServerUtil::server_root,
"logs", "$username.log";
open my $fh, ">>$log_path" or die "can't open $log_path: $!";
flock $fh, LOCK_EX;
print $fh $entry;
close $fh;
return Apache2::Const::OK;
}
1;</code></pre>
<p>First the handler tries to figure out what username the request is issued for, if it fails to match the URI, it simply returns <code>Apache2::Const::DECLINED</code>, letting other log handlers to do the logging. Though it could return <code>Apache2::Const::OK</code> since all other log handlers will be run anyway.</p>
<p>Next it builds the log entry, similar to the default <i>access_log</i> entry. It's comprised of remote IP, the current time, the uri, the return status and how many bytes were sent to the client as a response body.</p>
<p>Finally the handler appends this entry to the log file for the user the request was issued for. Usually it's safe to append short strings to the file without being afraid of messing up the file, when two files attempt to write at the same time, but just to be on the safe side the handler exclusively locks the file before performing the writing.</p>
<p>To configure the handler simply enable the module with the <code>PerlLogHandler</code> directive, for the desired URI namespace (starting with : <i>/~</i> in our example):</p>
<pre><code> <LocationMatch "^/~">
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlLogHandler MyApache2::LogPerUser
Options +ExecCGI
</LocationMatch></code></pre>
<p>After restarting the server and issuing requests to the following URIs:</p>
<pre><code> http://localhost/~stas/test.pl
http://localhost/~eric/test.pl
http://localhost/~stas/date.pl</code></pre>
<p>The <code>MyApache2::LogPerUser</code> handler will append to <i>logs/stas.log</i>:</p>
<pre><code> 127.0.0.1 [Sat Aug 31 01:50:38 2002] "/~stas/test.pl" 200 8
127.0.0.1 [Sat Aug 31 01:50:40 2002] "/~stas/date.pl" 200 44</code></pre>
<p>and to <i>logs/eric.log</i>:</p>
<pre><code> 127.0.0.1 [Sat Aug 31 01:50:39 2002] "/~eric/test.pl" 200 8</code></pre>
<p>It's important to notice that <code>PerlLogHandler</code> can be configured for any subsection of the site, no matter whether it's served by a mod_perl response handler or not. For example to run the handler from our example for all requests to the server, simply add to <i>httpd.conf</i>:</p>
<pre><code> <Location />
PerlLogHandler MyApache2::LogPerUser
</Location></code></pre>
<p>Since the <code>PerlLogHandler</code> phase is of type <code><a>RUN_ALL</a></code>, all other logging handlers will be called as well.</p>
<h2 id="PerlCleanupHandler1">PerlCleanupHandler</h2>
<p>There is no <i>cleanup</i> Apache phase, it exists only inside mod_perl. It is used to execute some code immediately after the request has been served (the client went away) and before the request object is destroyed.</p>
<p>There are several usages for this use phase. The obvious one is to run a cleanup code, for example removing temporarily created files. The less obvious is to use this phase instead of <code><a href="#PerlLogHandler">PerlLogHandler</a></code> if the logging operation is time consuming. This approach allows one to free the client as soon as the response is sent.</p>
<p>This phase is of type <code><a>RUN_ALL</a></code>.</p>
<p>The handler's configuration scope is <code><a>DIR</a></code>.</p>
<p><b>Arguments</b></p>
<p>See the <a>HTTP Request Handler Skeleton</a> for a description of handler arguments.</p>
<p><b>Return</b></p>
<p>See <a>Stacked Handlers</a> for a description of handler return codes.</p>
<p><b>Examples</b></p>
<p>There are two ways to register and run cleanup handlers:</p>
<dl>
<dt id="Using-the-PerlCleanupHandler-phase">1 Using the <code>PerlCleanupHandler</code> phase</dt>
<dd>
<pre><code> PerlCleanupHandler MyApache2::Cleanup</code></pre>
<p>or:</p>
<pre><code> $r->push_handlers(PerlCleanupHandler => \&cleanup);</code></pre>
<p>This method is identical to all other handlers.</p>
<p>In this technique the <code>cleanup()</code> callback accepts <code>$r</code> as its only argument.</p>
</dd>
<dt id="Using-cleanup_register-acting-on-the-request-objects-pool">2 Using <code>cleanup_register()</code> acting on the request object's pool</dt>
<dd>
<p>Since a request object pool is destroyed at the end of each request, we can use <code><a>cleanup_register</a></code> to register a cleanup callback which will be executed just before the pool is destroyed. For example:</p>
<pre><code> $r->pool->cleanup_register(\&cleanup, $arg);</code></pre>
<p>The important difference from using the <code>PerlCleanupHandler</code> handler, is that here you can pass an optional arbitrary argument to the callback function, and no <code>$r</code> argument is passed by default. Therefore if you need to pass any data other than <code>$r</code> you may want to use this technique.</p>
</dd>
</dl>
<p>Here is an example where the cleanup handler is used to delete a temporary file. The response handler is running <code>ls -l</code> and stores the output in temporary file, which is then used by <code>$r->sendfile</code> to send the file's contents. We use <code>push_handlers()</code> to push <code>PerlCleanupHandler</code> to unlink the file at the end of the request.</p>
<pre><code> #file:MyApache2/Cleanup1.pm
#-------------------------
package MyApache2::Cleanup1;
use strict;
use warnings FATAL => 'all';
use File::Spec::Functions qw(catfile);
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::RequestUtil ();
use Apache2::Const -compile => qw(OK DECLINED);
use APR::Const -compile => 'SUCCESS';
my $file = catfile "/tmp", "data";
sub handler {
my $r = shift;
$r->content_type('text/plain');
local @ENV{qw(PATH BASH_ENV)};
qx(/bin/ls -l > $file);
my $status = $r->sendfile($file);
die "sendfile has failed" unless $status == APR::Const::SUCCESS;
$r->push_handlers(PerlCleanupHandler => \&cleanup);
return Apache2::Const::OK;
}
sub cleanup {
my $r = shift;
die "Can't find file: $file" unless -e $file;
unlink $file or die "failed to unlink $file";
return Apache2::Const::OK;
}
1;</code></pre>
<p>Next we add the following configuration:</p>
<pre><code> <Location /cleanup1>
SetHandler modperl
PerlResponseHandler MyApache2::Cleanup1
</Location></code></pre>
<p>Now when a request to <i>/cleanup1</i> is made, the contents of the current directory will be printed and once the request is over the temporary file is deleted.</p>
<p>This response handler has a problem of running in a multi-process environment, since it uses the same file, and several processes may try to read/write/delete that file at the same time, wrecking havoc. We could have appended the process id <code>$$</code> to the file's name, but remember that mod_perl 2.0 code may run in the threaded environment, meaning that there will be many threads running in the same process and the <code>$$</code> trick won't work any longer. Therefore one really has to use this code to create unique, but predictable, file names across threads and processes:</p>
<pre><code> sub unique_id {
require Apache2::MPM;
require APR::OS;
return Apache2::MPM->is_threaded
? "$$." . ${ APR::OS::current_thread_id() }
: $$;
}</code></pre>
<p>In the threaded environment it will return a string containing the process ID, followed by a thread ID. In the non-threaded environment only the process ID will be returned. However since it gives us a predictable string, they may still be a non-satisfactory solution. Therefore we need to use a random string. We can either either Perl's <code>rand</code>, some CPAN module or the APR's <code>APR::UUID</code>:</p>
<pre><code> sub unique_id {
require APR::UUID;
return APR::UUID->new->format;
}</code></pre>
<p>Now the problem is how do we tell the cleanup handler what file should be cleaned up? We could have stored it in the <code>$r->notes</code> table in the response handler and then retrieve it in the cleanup handler. However there is a better way - as mentioned earlier, we can register a callback for request pool cleanup, and when using this method we can pass an arbitrary argument to it. Therefore in our case we choose to pass the file name, based on random string. Here is a better version of the response and cleanup handlers, that uses this technique:</p>
<pre><code> #file: MyApache2/Cleanup2.pm
#-------------------------
package MyApache2::Cleanup2;
use strict;
use warnings FATAL => 'all';
use File::Spec::Functions qw(catfile);
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::RequestUtil ();
use APR::UUID ();
use APR::Pool ();
use Apache2::Const -compile => qw(OK DECLINED);
use APR::Const -compile => 'SUCCESS';
my $file_base = catfile "/tmp", "data-";
sub handler {
my $r = shift;
$r->content_type('text/plain');
my $file = $file_base . APR::UUID->new->format;
local @ENV{qw(PATH BASH_ENV)};
qx(/bin/ls -l > $file);
my $status = $r->sendfile($file);
die "sendfile has failed" unless $status == APR::Const::SUCCESS;
$r->pool->cleanup_register(\&cleanup, $file);
return Apache2::Const::OK;
}
sub cleanup {
my $file = shift;
die "Can't find file: $file" unless -e $file;
unlink $file or die "failed to unlink $file";
return Apache2::Const::OK;
}
1;</code></pre>
<p>Similarly to the first handler, we add the configuration:</p>
<pre><code> <Location /cleanup2>
SetHandler modperl
PerlResponseHandler MyApache2::Cleanup2
</Location></code></pre>
<p>And now when requesting <i>/cleanup2</i> we still get the same output -- the listing of the current directory -- but this time this code will work correctly in the multi-processes/multi-threaded environment and temporary files get cleaned up as well.</p>
<h3 id="Possible-Caveats">Possible Caveats</h3>
<p><code>PerlCleanupHandler</code> may fail to be completed on server shutdown/graceful restart since Apache will kill the registered handlers via SIGTERM, before they had a chance to run or even in the middle of its execution. See: http://marc.theaimsgroup.com/?t=106387845200003&r=1&w=2 http://marc.theaimsgroup.com/?l=apache-modperl-dev&m=106427616108596&w=2</p>
<h1 id="Miscellaneous-Issues">Miscellaneous Issues</h1>
<h2 id="Handling-HEAD-Requests">Handling HEAD Requests</h2>
<p>In order to avoid the overhead of sending the data to the client when the request is of type HEAD in mod_perl 1.0 we <a>used to return early</a> from the handler:</p>
<pre><code> return Apache2::Const::OK if $r->header_only;</code></pre>
<p>This logic should not be used in mod_perl 2.0, because Apache 2.0 automatically discards the response body for HEAD requests. It expects the full body to generate the correct set of response headers, if you don't send the body you may encounter problems.</p>
<p>(You can also read the comment in for <code>ap_http_header_filter()</code> in <i>modules/http/http_protocol.c</i> in the Apache 2.0 source.)</p>
<h2 id="Content-Length-Response-Header"><code>Content-Length</code> Response Header</h2>
<p>You may encounter some issues with the C-L (<code>Content-Length</code>) header. Some of them are discussed here.</p>
<ul>
<li><p>The special case of <code>Content-Length: 0</code></p>
<p>Since Apache proclaims itself governor of the C-L header via the C-L filter (ap_content_length_filter at <i>httpd-2.0/server/protocol.c</i>), for the most part <code>GET</code> and <code>HEAD</code> behave exactly the same. However, when Apache sees a <code>HEAD</code> request with a C-L header of zero it takes special action and removes the C-L header. This is done to protect against handlers that called <code>$r->header_only</code> (<a href="#Handling_HEAD_Requests">which was ok in 1.3 but is not in 2.0</a>). Therefore, <code>GET</code> and <code>HEAD</code> behave identically, except when the content handler (and/or filters) end up sending no content. For more details refer to the lengthy comments in <code>ap_http_header_filter()</code> in <i>httpd-2.0/modules/http/http_protocol.c</i>).</p>
<p>For more discussion on why it is important to get HEAD requests right, see these threads from the mod_perl list:</p>
<pre><code> http://marc.theaimsgroup.com/?l=apache-modperl&m=108647669726915&w=2
http://marc.theaimsgroup.com/?t=109122984600001&r=1&w=2</code></pre>
<p>as well as this bug report from mozilla, which shows how <code>HEAD</code> requests are used in the wild:</p>
<pre><code> http://bugzilla.mozilla.org/show_bug.cgi?id=245447</code></pre>
</li>
<li><p>Not getting <code>Content-Length</code> header with <code>HEAD</code> requests</p>
<p>Even though the spec says that content handlers should send an identical response for GET and HEAD requests, some folks try to <a href="#Handling_HEAD_Requests">avoid the overhead of generating the response body</a>, which Apache is going to discard anyway for HEAD requests. The following discussion assumes that we deal with a HEAD request.</p>
<p>When Apache sees EOS and no headers and no response body were sent, <code>ap_content_length_filter()</code> (<i>httpd-2.0/server/protocol.c</i>) sets C-L to 0. Later on <code>ap_http_header_filter()</code> (<i>httpd-2.0/modules/http/http_protocol.c</i>) removes the C-L header for the HEAD requests.</p>
<p>The workaround is to force the sending of the response headers, before <code>EOS</code> was sent (which happens when the response handler returns). The simplest solution is to use rflush():</p>
<pre><code> if ($r->header_only) { # HEAD
$body_len = calculate_body_len();
$r->set_content_length($body_len);
$r->rflush;
}
else { # GET
# generate and send the body
}</code></pre>
<p>now if the handler sets the C-L header it'll be delivered to the client unmodified.</p>
</li>
</ul>
<h1 id="Misc-Notes">Misc Notes</h1>
<p>These items will need to be extended and integrated in this or other HTTP related documents:</p>
<ul>
<li><p>front-end back-end setup: mod_proxy+X-Forwarded-For</p>
<p>apache-1.3:</p>
<p>frontend: mod_proxy_add_forward http://develooper.com/code/mpaf/</p>
<p>backend: mod_rpaf (reverse proxy add forward): http://stderr.net/apache/rpaf/</p>
<p>apache-2.x:</p>
<p>frontend: mod_proxy</p>
<p>backend: mod_rpaf: http://stderr.net/apache/rpaf/</p>
</li>
</ul>
<h1 id="Extending-HTTP-Protocol">Extending HTTP Protocol</h1>
<p>Extending HTTP under mod_perl is a trivial task. Look at <a href="#PerlHeaderParserHandler">the example of adding a new method <code>EMAIL</code></a> for details.</p>
<h1 id="HTTP-Status-Codes">HTTP Status Codes</h1>
<p>The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems. It is a generic, stateless, protocol which can be used for many tasks beyond its use for hypertext, such as name servers and distributed object management systems, through extension of its request methods, error codes and headers. A feature of HTTP is the typing and negotiation of data representation, allowing systems to be built independently of the data being transferred.</p>
<p>HTTP 1.0 is described in Requests For Comments (RFC) 1945. HTTP 1.1 is the latest version of the specifications and as of this writing HTTP 1.1 is covered in RFC 2616.</p>
<p>When writing mod_perl applications, usually only a small subset of HTTP response codes is used, but sometimes you need to know others as well. We will give a short description of each code and you will find the extended explanation in the appropriate RFC. (Section 9 in RFC 1945 and section 10 in RFC 2616). You can always find the latest link to these RFCs at the Web Consortium site, <i>http://www.w3.org/Protocols/</i>.</p>
<p>While HTTP 1.1 is widely supported, HTTP 1.0 still remains the mainstream standard. Therefore we will supply a summary of the both versions including the corresponding Apache constants.</p>
<p>In mod_perl these constants can be accessed the <code><a>Apache::Constants</a></code> package (e.g., to access the HTTP_OK constant use <code>Apache::Constants::HTTP_OK</code>). See the <code><a>Apache::Constants</a></code> manpage for more information.</p>
<p>In mod_perl2 these constants can be accessed the <code><a>Apache2::Const</a></code> package (e.g., to access the HTTP_OK constant use <code>Apache2::Const::HTTP_OK</code>). See the <code><a>Apache2::Const</a></code> manpage for more information.</p>
<h2 id="HTTP-1.0-Status-Codes">HTTP 1.0 Status Codes</h2>
<ul>
<li><p>Successful 2xx:</p>
<pre><code> 200 HTTP_OK OK
201 HTTP_CREATED Created
202 HTTP_ACCEPTED Accepted
204 HTTP_NO_CONTENT No Content</code></pre>
</li>
<li><p>Redirection 3xx:</p>
<pre><code> 301 HTTP_MOVED_PERMANENTLY Multiple Choices
302 HTTP_MOVED_TEMPORARILY Moved Permanently
303 HTTP_SEE_OTHER Moved Temporarily
304 HTTP_NOT_MODIFIED Not Modified</code></pre>
</li>
<li><p>Client Error 4xx:</p>
<pre><code> 400 HTTP_BAD_REQUEST Bad Request
401 HTTP_UNAUTHORIZED Unauthorized
403 HTTP_FORBIDDEN Forbidden
404 HTTP_NOT_FOUND Not Found</code></pre>
</li>
<li><p>Server Error 5xx:</p>
<pre><code> 500 HTTP_INTERNAL_SERVER_ERROR Internal Server Error
501 HTTP_NOT_IMPLEMENTED Not Implemented
502 HTTP_BAD_GATEWAY Bad Gateway
503 HTTP_SERVICE_UNAVAILABLE Service UnavailableStatus Codes</code></pre>
</li>
</ul>
<h2 id="HTTP-1.1-Status-Codes">HTTP 1.1 Status Codes</h2>
<ul>
<li><p>Informational 1xx:</p>
<pre><code> 100 HTTP_CONTINUE Continue
101 HTTP_SWITCHING_PROTOCOLS Switching Protocols</code></pre>
</li>
<li><p>Successful 2xx:</p>
<pre><code> 200 HTTP_OK OK
201 HTTP_CREATED Created
202 HTTP_ACCEPTED Accepted
203 HTTP_NON_AUTHORITATIVE Non-Authoritative Information
204 HTTP_NO_CONTENT No Content
205 HTTP_RESET_CONTENT Reset Content
206 HTTP_PARTIAL_CONTENT Partial Content</code></pre>
</li>
<li><p>Redirection 3xx:</p>
<pre><code> 300 HTTP_MULTIPLE_CHOICES Multiple Choices
301 HTTP_MOVED_PERMANENTLY Moved Permanently
302 HTTP_MOVED_TEMPORARILY Found
303 HTTP_SEE_OTHER See Other
304 HTTP_NOT_MODIFIED Not Modified
305 HTTP_USE_PROXY Use Proxy
306 (Unused)
307 HTTP_TEMPORARY_REDIRECT Temporary Redirect</code></pre>
</li>
<li><p>Client Error 4xx:</p>
<pre><code> 400 HTTP_BAD_REQUEST Bad Request
401 HTTP_UNAUTHORIZED Unauthorized
402 HTTP_PAYMENT_REQUIRED Payment Required
403 HTTP_FORBIDDEN Forbidden
404 HTTP_NOT_FOUND Not Found
405 HTTP_METHOD_NOT_ALLOWED Method Not Allowed
406 HTTP_NOT_ACCEPTABLE Not Acceptable
407 HTTP_PROXY_AUTHENTICATION_REQUIRED Proxy Authentication Required
408 HTTP_REQUEST_TIMEOUT Request Timeout
409 HTTP_CONFLICT Conflict
410 HTTP_GONE Gone
411 HTTP_LENGTH REQUIRED Length Required
412 HTTP_PRECONDITION_FAILED Precondition Failed
413 HTTP_REQUEST_ENTITY_TOO_LARGE Request Entity Too Large
414 HTTP_REQUEST_URI_TOO_LARGE Request-URI Too Long
415 HTTP_UNSUPPORTED_MEDIA_TYPE Unsupported Media Type
416 HTTP_RANGE_NOT_SATISFIABLE Requested Range Not Satisfiable
417 HTTP_EXPECTATION_FAILED Expectation Failed</code></pre>
</li>
<li><p>Server Error 5xx:</p>
<pre><code> 500 HTTP_INTERNAL_SERVER_ERROR Internal Server Error
501 HTTP_NOT IMPLEMENTED Not Implemented
502 HTTP_BAD_GATEWAY Bad Gateway
503 HTTP_SERVICE_UNAVAILABLE Service Unavailable
504 HTTP_GATEWAY_TIME_OUT Gateway Timeout
505 HTTP_VERSION_NOT_SUPPORTED HTTP Version Not Supported</code></pre>
</li>
</ul>
<h2 id="References">References</h2>
<p>All the information related to web protocols can be found at the World Wide Web Consortium site, <i>http://www.w3.org/Protocols/</i>.</p>
<p>There are many mirrors of the RFCs all around the world. One of the good starting points might be <i>http://www.rfc-editor.org/</i>.</p>
<p>The Eagle Book provided much of the HTTP constants material shown here <i>http://www.modperl.com/book/chapters/ch9.html#The_Apache_Constants_Class</i></p>
<h1 id="Maintainers">Maintainers</h1>
<p>Maintainer is the person(s) you should contact with updates, corrections and patches.</p>
<ul>
<li><p><a>The mod_perl development team and numerous contributors</a>.</p>
</li>
</ul>
<h1 id="Authors">Authors</h1>
<ul>
<li><p>Stas Bekman [http://stason.org/]</p>
</li>
</ul>
<p>Only the major authors are listed above. For contributors see the Changes file.</p>
</body>
</html>
|