stas 2002/12/15 09:32:04 Modified: src/docs/2.0 TODO src/docs/2.0/devel/core apache_integration.pod src/docs/2.0/user config.cfg src/docs/2.0/user/coding coding.pod src/docs/2.0/user/config config.pod src/docs/2.0/user/intro start_fast.pod Log: a bunch of docco fixes and improvements Revision Changes Path 1.4 +231 -1 modperl-docs/src/docs/2.0/TODO Index: TODO =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/TODO,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- TODO 4 Dec 2002 02:58:26 -0000 1.3 +++ TODO 15 Dec 2002 17:32:04 -0000 1.4 @@ -52,9 +52,239 @@ If you create an apr object and register your own cleanup, you still have that object until your registered cleanup is finished. +--- + +Need to integrate the following example, removed from overview.pod, in +protocols.pod: + + +=head2 Apache::CommandServer + +Our first protocol handler example took advange of Apache's server +framework, but did not tap into any other modules. The next example +is based on the example in the "TCP Servers with IO::Socket" section +of the I<perlipc> manpage. Of course, we don't need C<IO::Socket> +since Apache takes care of those details for us. The rest of that +example can still be used to illustrate implementing a simple text +protocol. In this case, one where a command is sent by the client to +be executed on the server side, with results sent back to the client. + +The C<Apache::CommandServer> handler will support four commands: +C<motd>, C<date>, C<who> and C<quit>. These are probably not commands +which can be exploited, but should we add such commands, we'll want to +limit access based on ip address/hostname, authentication and +authorization. Protocol handlers need to take care of these tasks +themselves, since we bypass the HTTP protocol handler. + +As with all C<PerlProcessConnectionHandlers>, we are passed an +C<Apache::Connection> object as the first argument. Again, we will be +directly accessing the client socket via the I<client_socket> method. +The I<login> subroutine is called to check if access by this client +should be allowed. This routine makes up for what we lost with the +core HTTP protocol handler bypassed. First we call the +C<Apache::RequestRec> I<new> method, which returns a I<request_rec> +object, just like that which is passed at request time to +C<Perl*Handlers> and returned by the subrequest API methods, +I<lookup_uri> and I<lookup_file>. However, this "fake request" does +not run handlers for any of the phases, it simply returns an object +which we can use to do that ourselves. The C<location_merge> method +is passed the "location" for this request, it will look up the +C<E<lt>LocationE<gt>> section that matches the given name and merge it +with the default server configuration. For example, should we only +wish to allow access to this server from certain locations: + + <Location Apache::CommandServer> + deny from all + allow from 10.* + </Location> + +The I<location_merge> method only looks up and merges the +configuration, we still need to apply it. This is done in I<for> +loop, iterating over three methods: I<run_access_checker>, +I<run_check_user_id> and I<run_auth_checker>. These methods will call +directly into the Apache functions that invoke module handlers for +these phases and will return an integer status code, such as C<OK>, +C<DECLINED> or C<FORBIDDEN>. If I<run_access_check> returns something +other than C<OK> or C<DECLINED>, that status will be propagated up to +the handler routine and then back up to Apache. Otherwise, the access +check passed and the loop will break unless I<some_auth_required> +returns true. This would be false given the previous configuration +example, but would be true in the presense of a I<require> directive, +such as: + + <Location Apache::CommandServer> + deny from all + allow from 10.* + require user dougm + </Location> + +Given this configuration, I<some_auth_required> will return true. The +I<user> method is then called, which will return false if we have not +yet authenticated. A I<prompt> utility is called to read the username +and password, which are then injected into the I<headers_in> table +using the I<set_basic_credentials> method. The I<Authenticate> field +in this table is set to a base64 encoded value of the +username:password pair, exactly the same format a browser would send +for I<Basic authentication>. Next time through the loop +I<run_check_user_id> is called, which will in turn invoke any +authentication handlers, such as I<mod_auth>. When I<mod_auth> calls +the I<ap_get_basic_auth_pw()> API function (as all Basic auth modules +do), it will get back the username and password we injected. If we +fail authentication a B<401> status code is returned which we +propagate up. Otherwise, authorization handlers are run via +I<run_auth_checker>. Authorization handlers normally need the I<user> +field of the I<request_rec> for its checks and that field was filled +in when I<mod_auth> called I<ap_get_basic_auth_pw()>. + +Provided login is a success, a welcome message is printed and main +request loop entered. Inside the loop the I<getline> function returns +just one line of data, with newline characters stripped. If the +string sent by the client is in our command table, the command is then +invoked, otherwise a usage message is sent. If the command does not +return a true value, we break out of the loop. Let's give it a try +with this configuration: + + Listen 8085 + <VirtualHost _default_:8085> + PerlProcessConnectionHandler Apache::CommandServer + + <Location Apache::CommandServer> + allow from 127.0.0.1 + require user dougm + satisfy any + AuthUserFile /tmp/basic-auth + </Location> + </VirtualHost> + + % telnet localhost 8085 + Trying 127.0.0.1... + Connected to localhost (127.0.0.1). + Escape character is '^]'. + Login: dougm + Password: foo + Welcome to Apache::CommandServer + Available commands: motd date who quit + motd + Have a lot of fun... + date + Mon Mar 12 19:20:10 PST 2001 + who + dougm tty1 Mar 12 00:49 + dougm pts/0 Mar 12 11:23 + dougm pts/1 Mar 12 14:08 + dougm pts/2 Mar 12 17:09 + quit + Connection closed by foreign host. + +=head2 Apache::CommandServer Source + + package Apache::CommandServer; + + use strict; + use Apache::Connection (); + use APR::Socket (); + use Apache::HookRun (); + + use Apache::Const -compile => qw(OK DECLINED); + + my @cmds = qw(motd date who quit); + my %commands = map { $_, \&{$_} } @cmds; + + sub handler { + my Apache::Connection $c = shift; + my APR::Socket $socket = $c->client_socket; + + if ((my $rc = login($c)) != Apache::OK) { + $socket->send("Access Denied\n"); + return $rc; + } + + $socket->send("Welcome to " . __PACKAGE__ . + "\nAvailable commands: @cmds\n"); + + for (;;) { + my $cmd; + next unless $cmd = getline($socket); + + if (my $sub = $commands{$cmd}) { + last unless $sub->($socket) == APR::SUCCESS; + } + else { + $socket->send("Commands: @cmds\n"); + } + } + + return Apache::OK; + } + + sub login { + my $c = shift; + + my $r = Apache::RequestRec->new($c); + $r->location_merge(__PACKAGE__); + + for my $method (qw(run_access_checker run_check_user_id run_auth_checker)) { + my $rc = $r->$method(); + + if ($rc != Apache::OK and $rc != Apache::DECLINED) { + return $rc; + } + + last unless $r->some_auth_required; + + unless ($r->user) { + my $socket = $c->client_socket; + my $username = prompt($socket, "Login"); + my $password = prompt($socket, "Password"); + + $r->set_basic_credentials($username, $password); + } + } + + return Apache::OK; + } + + sub getline { + my $socket = shift; + my $line; + $socket->recv($line, 1024); + return unless $line; + $line =~ s/[\r\n]*$//; + return $line; + } + + sub prompt { + my($socket, $msg) = @_; + $socket->send("$msg: "); + getline($socket); + } + + sub motd { + my $socket = shift; + open my $fh, '/etc/motd' or return; + local $/; + my $status = $socket->send(scalar <$fh>); + close $fh; + return $status; + } + + sub date { + my $socket = shift; + $socket->send(scalar(localtime) . "\n"); + } + + sub who { + my $socket = shift; + $socket->send(scalar `who`); + } + + sub quit {1} + + 1; + __END__ + ---- --- 1.3 +33 -2 modperl-docs/src/docs/2.0/devel/core/apache_integration.pod Index: apache_integration.pod =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/devel/core/apache_integration.pod,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- apache_integration.pod 9 Dec 2002 16:39:34 -0000 1.2 +++ apache_integration.pod 15 Dec 2002 17:32:04 -0000 1.3 @@ -20,7 +20,7 @@ =head2 The Link Between mod_perl and httpd -I<mod_perl.c> defines a special structure: +I<mod_perl.c> includes a special data structure: module AP_MODULE_DECLARE_DATA perl_module = { STANDARD20_MODULE_STUFF, @@ -161,7 +161,7 @@ modperl_trace_level_set(s, NULL); } -=head1 The pre_config stage +=head1 The C<pre_config> Phase After Apache processes its command line arguments, creates various pools and reads the configuration file in, it runs the registered @@ -214,6 +214,37 @@ called for every section and subsection that includes mod_perl directives (META: or inherits from such a section even though specifies no mod_perl directives in it?). + +=head2 Virtual Hosts Fixup + +After the configuration tree is processed, C<ap_fixup_virtual_hosts()> +is called. One of the responsibilities of this function is to merge +the virtual hosts configuration objects with the base server's object. +If there are virtual hosts, C<merge_server_configs()> calls +C<modperl_config_srv_merge()> and C<modperl_config_dir_merge()> for +each virtual host, to perform this merge for mod_perl configuration +objects. + +META: is that's the place where everything restarts? it doesn't +restart under debugger since we run with NODETACH I believe. + +=head2 The I<open_logs> Phase + +After Apache processes the configuration it's time for the +I<open_logs> phase, executed by C<ap_run_open_logs()>. mod_perl has +registered the C<modperl_hook_init()> hook to be called for this phase. + +META: complete what happens at this stage in mod_perl + +META: why is it called modperl_hook_init and not open_logs? is it +because it can be called from other functions? + +=head2 The I<post_config> Phase + +Immediately after I<open_logs>, the I<post_config> phase follows. Here +C<ap_run_post_config()> calls C<modperl_hook_post_config()> + + =head1 Request Processing 1.18 +0 -1 modperl-docs/src/docs/2.0/user/config.cfg Index: config.cfg =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/config.cfg,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- config.cfg 9 Dec 2002 16:47:07 -0000 1.17 +++ config.cfg 15 Dec 2002 17:32:04 -0000 1.18 @@ -11,7 +11,6 @@ group => 'Introduction', chapters => [qw( intro/start_fast.pod - intro/what_is_new.pod overview/overview.pod design/design.pod )], 1.16 +29 -10 modperl-docs/src/docs/2.0/user/coding/coding.pod Index: coding.pod =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/coding/coding.pod,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- coding.pod 30 Aug 2002 12:23:07 -0000 1.15 +++ coding.pod 15 Dec 2002 17:32:04 -0000 1.16 @@ -155,15 +155,16 @@ know what you are doing. -=head1 Threads Coding Issues under mod_perl +=head1 Threads Coding Issues Under mod_perl The following sections discuss threading issues when running mod_perl under a threaded MPM. =head2 Thread-environment Issues -The only thing you have to worry about your code is that it's -thread-safe and that you don't use functions that affect all threads. +The "only" thing you have to worry about your code is that it's +thread-safe and that you don't use functions that affect all threads +in the same process. Perl 5.8.0 itself is a thread-safe. That means that operations like C<push()>, C<map()>, C<chomp()>, C<=>, C</>, C<+=>, etc. are @@ -172,8 +173,8 @@ by the perl functions are thread-safe. For example the function C<localtime()> is not thread-safe when the -implementation of asctime(3) is not thread-safe. Other usually -problematic functions include readdir(), srand(), etc. +implementation of C<asctime(3)> is not thread-safe. Other usually +problematic functions include C<readdir()>, C<srand()>, etc. Another important issue that shouldn't be missed is what some people refer to as I<thread-locality>. Certain functions executed in a single @@ -183,7 +184,12 @@ thread that C<chdir()>'ed to that directory. Other functions with similar effects include C<umask()>, C<chroot()>, etc. Currently there is no cure for this problem. You have to find these functions in your -code and replace them with different workarounds. +code and replace them with alternative solutions which don't incur +this problem. + +For more information refer to the I<perlthrtut> +(I<http://perldoc.com/perl5.8.0/pod/perlthrtut.html>) manpage. + =head2 Deploying Threads @@ -194,13 +200,26 @@ If you want to spawn your own threads, first of all study how the new ithreads Perl model works, by reading the I<perlthrtut>, I<threads> -and I<threads::shared> manpages. +(I<http://search.cpan.org/search?query=threads>) and +I<threads::shared> +(I<http://search.cpan.org/search?query=threads%3A%3Ashared>) manpages. Artur Bergman wrote an article which explains how to port pure Perl -modules to work properly with Perl ithreads. Issues with chdir() and -other functions that rely on shared process' datastructures are -discussed. http://www.perl.com/lpt/a/2002/06/11/threads.html +modules to work properly with Perl ithreads. Issues with C<chdir()> +and other functions that rely on shared process' datastructures are +discussed. I<http://www.perl.com/lpt/a/2002/06/11/threads.html>. + +=head2 Shared Variables + +Global variables are only global to the interpreter in which they are +created. Other interpreters from other threads can't access that +variable. Though it's possible to make existing variables shared +between several threads running in the same process by using the +function C<threads::shared::share()>. New variables can be shared by +using the I<shared> attribute when creating them. This feature is +documented in the I<threads::shared> +(I<http://search.cpan.org/search?query=threads%3A%3Ashared>) manpage. =head1 Maintainers 1.31 +3 -9 modperl-docs/src/docs/2.0/user/config/config.pod Index: config.pod =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/config/config.pod,v retrieving revision 1.30 retrieving revision 1.31 diff -u -r1.30 -r1.31 --- config.pod 6 Dec 2002 07:45:36 -0000 1.30 +++ config.pod 15 Dec 2002 17:32:04 -0000 1.31 @@ -1032,16 +1032,10 @@ =head1 Perl Interface to the Apache Configuration Tree -META: - -Apache::Directive - -t/response/TestApache/conftree.pm - - - - +META: any volunteers to write this section? see +t/response/TestApache/conftree.pm for examples of using the api. +L<Apache::Directive|docs::2.0::api::modperl_2.0::Apache::Directive>. 1.9 +25 -12 modperl-docs/src/docs/2.0/user/intro/start_fast.pod Index: start_fast.pod =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/intro/start_fast.pod,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- start_fast.pod 3 Sep 2002 05:02:18 -0000 1.8 +++ start_fast.pod 15 Dec 2002 17:32:04 -0000 1.9 @@ -9,15 +9,18 @@ =head1 Installation -First of all check that you have the L<mod_perl 2.0 +If you are a Win32 user, please refer to the L<Win32 installation +document|docs::2.0::os::win32::install>. + +First, L<download|download::index> the mod_perl 2.0 source. + +Before installing mod_perl, you need check that you have the +L<mod_perl 2.0 prerequisites|docs::2.0::user::install::install/Prerequisites>. In this chapter we assume that httpd was installed under I<$HOME/httpd/prefork>. -Next, download the mod_perl 2.0 source from: -I<http://perl.apache.org/download/>. - Now, configure mod_perl: % tar -xvzf mod_perl-2.x.xx.tar.gz @@ -42,6 +45,9 @@ =head1 Configuration +If you are a Win32 user, please refer to the L<Win32 configuration +document|docs::2.0::os::win32::config>. + Enable mod_perl built as DSO, by adding to I<httpd.conf>: LoadModule perl_module modules/mod_perl.so @@ -76,14 +82,12 @@ Check I<$HOME/httpd/prefork/logs/error_log> to see that the server has started and it's a right one. It should say something similar to: - [Tue Sep 03 12:34:57 2002] [notice] Apache/2.0.41-dev (Unix) - mod_perl/1.99_05-dev Perl/v5.8.0 mod_ssl/2.0.41-dev OpenSSL/0.9.6d + [Tue Sep 03 12:34:57 2002] [notice] Apache/2.0.44 (Unix) + mod_perl/1.99_07 Perl/v5.8.0 mod_ssl/2.0.44 OpenSSL/0.9.6g DAV/2 configured -- resuming normal operations - - =head1 Registry Scripts To enable registry scripts add to I<httpd.conf>: @@ -118,7 +122,10 @@ If that didn't work check the I<error_log> file. - +For more information on the registry scripts refer to the +C<L<ModPerl::Registry|docs::2.0::api::ModPerl-Registry::ModPerl::Registry>> +manapage. (XXX: on day there will a tutorial on registry, should port +it from 1.0's docs). =head1 Handler Modules @@ -127,6 +134,8 @@ response handler similar to the registry script from the previous section: + #file:MyApache/Rocks.pm + #---------------------- package MyApache::Rocks; use strict; @@ -179,9 +188,13 @@ =head1 Troubleshooting -If after reading the complete installation and configuration chapters -you are still having problems, please L<report -them|docs::2.0::user::help::help/Reporting_Problems>. +If after reading the complete +L<installation|docs::2.0::user::install::install> and L<configuration +chapters|docs::2.0::user::config::config> you are still having +problems, take a look at the L<troubleshooting +sections|docs::2.0::user::troubleshooting::troubleshooting>. If the problem +persist, please report them using the L<following +guidelines|docs::2.0::user::help::help/Reporting_Problems>.
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]