stas 2004/03/02 13:05:32 Modified: src/docs/2.0/user/coding coding.pod Log: - new: Generating HTTP Response Headers - update: Forcing HTTP Response Headers Out - new: registry section - new: registry: A Look Behind the Scenes - new: registry: Getting the $r Object Revision Changes Path 1.30 +187 -8 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.29 retrieving revision 1.30 diff -u -u -r1.29 -r1.30 --- coding.pod 12 Jan 2004 08:42:52 -0000 1.29 +++ coding.pod 2 Mar 2004 21:05:32 -0000 1.30 @@ -203,17 +203,106 @@ In the following sections we discuss the specifics of Apache behavior relevant to mod_perl developers. -=head2 Sending HTTP Response Headers +=head2 HTTP Response Headers + +=head3 Generating HTTP Response Headers + +The best approach for generating HTTP response headers is by using the +L<mod_perl API|docs::2.0::api::Apache::RequestRec>. Some common +headers have dedicated methods, others are set by manipulating the +C<L<headers_out|docs::2.0::api::Apache::RequestRec/C_headers_out_>> +table directly. + +For example to set the I<Content-type> header you should call +C<L<$r-E<gt>content_type|docs::2.0::api::Apache::RequestRec/C_content_type_>>: + + use Apache::RequestRec (); + $r->content_type('text/html'); + +To C<L<set|docs::2.0::api::APR::Table/C_set_>> a custom header +I<My-Header> you should call: + + use Apache::RequestRec (); + use APR::Table; + $r->headers_out->set(My-Header => "SomeValue"); + +If you are inside a registry script L<you can still +access|docs::2.0::user::coding::coding/Getting_the_C__r__Object> the +C<L<Apache::RequestRec|docs::2.0::api::Apache::RequestRec>> object. + +Howerever you can choose a slower method of generating headers by just +printing them out before printing any response. This will work only if +C<L<PerlOptions ++ParseHeaders|docs::2.0::user::config::config/C_ParseHeaders_>> is +in effect. For example: + + print "Content-type: text/html\n"; + print "My-Header: SomeValue\n"; + print "\n"; + +This method is slower since Apache needs to parse the text to identify +certain headers it needs to know about. It also has several +limitations which we will now discuss. + +When using this approach you must make sure that the C<STDOUT> +filehandle is not set to flush the data after each print (which is set +by the value of a special perl variable C<$|>). Here we assume that +STDOUT is the currently C<select()>ed filehandle and C<$|> affects it. + +For example this code won't work: + + local $| = 1; + print "Content-type: text/html\n"; + print "My-Header: SomeValue\n"; + print "\n"; + +Having a true C<$|> causes the first print() call to flush its data +immediately, which is sent to the internal HTTP header parser, which +will fail since it won't see the terminating C<"\n\n">. One solution +is to make sure that STDOUT won't flush immediately, like so: + + local $| = 0; + print "Content-type: text/html\n"; + print "My-Header: SomeValue\n"; + print "\n"; + +Notice that we C<local()>ize that change, so it L<won't affect any +other +code|docs::general::perl_reference::perl_reference/The_Scope_of_the_Special_Perl_Variables>. + +If you send headers line by line and their total length is bigger than +8k, you will have the header parser problem again, since mod_perl will +flush data when the 8k buffer gets full. In which case the solution is +not to print the headers one by one, but to buffer them all in a +variable and then print the whole set at once. + +Notice that you don't have any of these problems with mod_cgi, because +it ignores any of the flush attempts by Perl. mod_cgi simply opens a +pipe to the external process and reads any output sent from that +process at once. + +If you use C<$r> to set headers as explained at the beginning of this +section, you won't encounter any of these problems. + +Finally, If you don't want Apache to send its own headers and you want +to send your own set of headers (non-parsed headers handlers) use +explain the +C<L<$r-E<gt>assbackwards|docs::2.0::api::Apache::RequestRec/C_assbackwards_>> +method. Notice that registry handlers will do that for you if the +script's name start with the C<nph-> prefix. + + +=head3 Forcing HTTP Response Headers Out Apache 2.0 doesn't provide a method to force HTTP response headers sending (what used to be done by C<send_http_header()> in Apache 1.3). HTTP response headers are sent as soon as the first bits of the response body are seen by the special core output filter that -generates these headers. When the response handler send the first +generates these headers. When the response handler sends the first chunks of body it may be cached by the mod_perl internal buffer or even by some of the output filters. The response handler needs to -flush in order to tell all the components participating in the sending -of the response to pass the data out. +flush the output in order to tell all the components participating in +the sending of the response to pass the data out. For example if the handler needs to perform a relatively long-running operation (e.g. a slow db lookup) and the client may timeout if it @@ -230,11 +319,14 @@ } If this doesn't work, check whether you have configured any -third-party output filters for the resource in question. Improperly -written filter may ignore the orders to flush the data. +third-party output filters for the resource in question. L<Improperly +written +filter|docs::2.0::user::handlers::filters/Writing_Well_Behaving_Filters> +may ignore the command to flush the data. + + + -META: add a link to the notes on how to write well-behaved filters -at handlers/filters =head2 Sending HTTP Response Body @@ -246,11 +338,17 @@ the issues is that the HTTP response filters are not setup before the response phase. + + + =head1 Perl Specifics in the mod_perl Environment In the following sections we discuss the specifics of Perl behavior under mod_perl. + + + =head2 Request-localized Globals mod_perl 2.0 provides two types of C<SetHandler> handlers: @@ -295,6 +393,87 @@ You can still call C<CORE::exit> to kill the interpreter, again if you know what you are doing. + + + + +=head1 C<ModPerl::Registry> Handlers Family + +=head2 A Look Behind the Scenes + +If you have a CGI script F<test.pl>: + + #!/usr/bin/perl + print "Content-type: text/plain\n\n"; + print "Hello"; + +a typical registry family handler turns it into something like: + + package foo_bar_baz; + sub handler { + local $0 = "/full/path/to/test.pl"; + #line 1 test.pl + #!/usr/bin/perl + print "Content-type: text/plain\n\n"; + print "Hello"; + } + +Turning it into an almost full-fledged mod_perl handler. The only +difference is that it handles the return status for you. (META: more +details on return status needed.) + +It then executes it as: + + foo_bar_baz::handler($r); + +passing the C<L<$r|docs::2.0::api::Apache::RequestRec>> object as the +only argument to the C<handler()> function. + +Depending on the used registry handler the package is made of the file +path, the uri or anything else. Check the handler's documentation to +learn which method is used. + + + +=head2 Getting the C<$r> Object + +As explained in L<A Look Behind the Scenes|/A_Look_Behind_the_Scenes> +the C<$r> object is always passed to the registry script's special +function C<handler> as the first and the only argument, so you can get +this object by accessing C<@_>, since: + + my $r = shift; + print "Content-type: text/plain\n\n"; + print "Hello"; + +is turned into: + + sub handler { + my $r = shift; + print "Content-type: text/plain\n\n"; + print "Hello"; + } + +behind the scenes. Now you can use C<$r> to call various mod_perl +methods, e.g. rewriting the script as: + + my $r = shift; + $r->content_type('text/plain'); + $r->print(); + +If you are deep inside some code and can't get to the entry point to +reach for C<$r>, you can use +C<L<Apache-E<gt>request|docs::2.0::api::Apache::RequestUtil/C_request_>>. + + + + + + + + + + =head1 Threads Coding Issues Under mod_perl
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]