http://www.perlmonks.org?node_id=752871

gfairweather has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I had a problem whereby when sending a '304 Not Changed' Perl/Apache would send a Content-Type, which the HTTP/1.1 protocol states should not be sent with this status. rfc2616 Section 10.3.5

Try:

print "Status: 304 Not Changed\n\n";

or using CGI

print header(-status => '304 Not Changed');

and you will see the Content-Type header is generated.

I was directed towards using NPH CGI NPH and so prepended 'nph-' to my script name and added all the appropriate headers that were prevously filled in by Apache.

Now with this code the Content-Type is no longer sent, which is what is specified in the rfc

print "Status: 304 Not Changed\n\n";

But using CGI

print header(-status => '304 Not Changed');

With this the Content-Type header is still generated.

So I used the print method and not the CGI method for sending HTTP headers.

Now my issue is that Connection: Keep-Alive no longer functions, I can create and send the headers to the client but when my script exits the connection is closed. I tested this using telnet and performing GET requests. rfc2616 Section 14.10 Apache Keep-Alive

So my questions are, can I interact with Apache in some way so that I can use Connection: Keep-Alive when running a NPH script or is there some other solution that I have missed along the way that fixes both the 304 and Keep-Alive issue? (I am using Perl 5.6.1 and Apache 1.3.26 on a hosted server over which I have little control.)

Any help or pointers are greatly appreciated

Replies are listed 'Best First'.
Re: NPH and Connection: Keep-Alive
by ikegami (Patriarch) on Mar 24, 2009 at 13:53 UTC
    For a connection to be reused, the client needs to know where the response ends. Same with the server and the request. This is done by specifying the Content-Length header.

    Update: -type => '' to prevent Content-Type.

      Thank you, this resolves the problem with the Content-Type being sent when the script is NPH and using the CGI method. However, it does not appear to resolve the Connection: Keep-Alive issue, the connection is still being closed when the script finishes.

      My script is calculating the body length and sending the Content-Length header, aswell as any other headers that are specified in the rfc.

      304 Example using:
      print header(-status => '304 Not Modified', -nph => 1, -type => '', -connection => 'Keep-Alive', 'Keep-Alive' => 'timeout=15, max=100');

      Here is the connection closing after issueing the 304:

      GET /nph-test.pl HTTP/1.1 Host: www.xyz.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.7 +) Gecko/2009021910 Firefox/3.0.7 (.NET CLR 3.5.30729) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0. +8,text/vnd.wap.wml;q=0.6 Accept-Language: en-gb,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache HTTP/1.1 304 Not Modified Server: Apache/1.3.26 (Unix) (Red-Hat/Linux) FrontPage/5.0.2.2510 Status: 304 Not Modified Date: Tue, 24 Mar 2009 14:40:18 GMT keep-alive: timeout=15, max=100 connection: Keep-Alive Connection closed by foreign host.

      And here after serving a page:

      GET /nph-servefiles.pl HTTP/1.1 Host: www.xyz.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.7 +) Gecko/2009021910 Firefox/3.0.7 (.NET CLR 3.5.30729) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0. +8,text/vnd.wap.wml;q=0.6 Accept-Language: en-gb,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache HTTP/1.1 200 OK Accept-Ranges: none Expires: Sun, 20 Mar 2011 18:56:47 GMT Server: Apache/1.3.26 (Unix) (Red-Hat/Linux) FrontPage/5.0.2.2510 Vary: Accept,Accept-Encoding,User-Agent Content-Length: 20 Etag: "06f0001f16dfd8b9632cc9640d62e5e0-gzip" Cache-Control: s-maxage=1209600,proxy-revalidate,must-revalidate, max- +age=62741536 Content-Encoding: gzip Last-Modified: Tue, 24 Mar 2009 02:04:17 GMT Date: Tue, 24 Mar 2009 14:56:01 GMT Connection: Keep-Alive Content-Type: application/xhtml+xml, charset=utf-8 Keep-Alive: timeout=15,max=100 Connection closed by foreign host.

      And here 2 requests not using a script:

      GET /images/validate.gif HTTP/1.1 Host: www.xyz.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.7 +) Gecko/2009021910 Firefox/3.0.7 (.NET CLR 3.5.30729) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0. +8,text/vnd.wap.wml;q=0.6 Accept-Language: en-gb,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache HTTP/1.1 200 OK Date: Tue, 24 Mar 2009 14:44:31 GMT Server: Apache/1.3.26 (Unix) (Red-Hat/Linux) FrontPage/5.0.2.2510 Cache-Control: s-maxage=1209600,proxy-revalidate,must-revalidate, max- +age=62741536 Expires: Sun, 20 Mar 2011 18:56:47 GMT Last-Modified: Fri, 20 Mar 2009 18:56:47 GMT ETag: "92042c-1bd8-49c3e6ef" Accept-Ranges: bytes Content-Length: 7128 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: image/gif GET /images/validate.gif HTTP/1.1 Host: www.xyz.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.7 +) Gecko/2009021910 Firefox/3.0.7 (.NET CLR 3.5.30729) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0. +8,text/vnd.wap.wml;q=0.6 Accept-Language: en-gb,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache HTTP/1.1 200 OK Date: Tue, 24 Mar 2009 14:44:48 GMT Server: Apache/1.3.26 (Unix) (Red-Hat/Linux) FrontPage/5.0.2.2510 Cache-Control: s-maxage=1209600,proxy-revalidate,must-revalidate, max- +age=62741519 Expires: Sun, 20 Mar 2011 18:56:47 GMT Last-Modified: Fri, 20 Mar 2009 18:56:47 GMT ETag: "92042c-1bd8-49c3e6ef" Accept-Ranges: bytes Content-Length: 7128 Keep-Alive: timeout=15, max=99 Connection: Keep-Alive Content-Type: image/gif

      Any further information appreciated

        I'm not experienced in this area. I'll have to get back to you later today after having time to do some testing.
Re: NPH and Connection: Keep-Alive
by eric256 (Parson) on Mar 24, 2009 at 21:59 UTC

    After your script ends, how would you send more information to the browser?

    Here is my simplified understanding of your question: Browser requests page from Server. Server runs script, script returns partial output, Server sends output to browser, script ends...Server sends what to the browser?</>

    Here is my simplified understanding of what I think you want: Browser requests page from Server. Server runs script, script returns partial output, Server sends output to browser, script loops and sends more info to the server, server continues sending output to the browser until the script ends.</>


    ___________
    Eric Hodges

      After the script ends the client will have the HTML page and the browser will then request the css, the javascript and the images that are linked in the document.

      Trying to put it simply, the script runs from top to bottom with 2 exit points. If cache control is met by comparing last modifed date and etag then the script exits with a 304. Otherwise the HTML is built from a template and held in a scalar, so the length can be calculated, the headers are output followed by the body and then the script exits.

      My expectation, based on how Apache serves files, is that if the browser sends Keep-Alive then the server responds with Keep-Alive, a timeout value and max objects value. If the next request is within the timeout value and the max objects has not been met then the request is served on the open connection, the timer is reset and the max object decremented by 1. If there is no further request within the timeout or the max objects is met then the connection is closed by the server. You can partially see this in the two header traces that I posted above.

      What I see from using telnet/browser and wireshark is that as soon as the script exits, instead of the connection being kept alive, the server sends (FIN,ACK), the broswer acknowledges (ACK) and then sends (FIN,ACK) and the server acknowledges (ACK) and the connection is closed immediately. Any further requests for the css, javascript and images open a new connection and keep-alives function as expected.

      What I'm trying to figure out is how do I replicate the normal Apache behavior for keep-alive. I mimic the headers exactly but Apache does not honour what has been sent. My assumption is that it's to do with the fact that it's NPH. Normally Apache would append these headers. What I need to be able to do is access the Apache timeout value and the max objects value so I can set those appropriately and inform Apache to decrement the max objects value and have Apache not tear down the connection.

      That's my understanding and I hope that makes sense.

      Thanks for your interest but the issue has been resolved and I no longer need to work the problem.