|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2017-01-14 18:38 UTC] markamery at btinternet dot com
Description:
------------
Running under mod_php, calling
header('HTTP/1.1 200 OK');
seems to prevent the connection from being closed once the PHP script finishes. This can be demonstrated by, for instance, hitting the script with ab (the Apache benchmark tool), which (unlike most HTTP clients, including browsers) only considers a request to have finished once the connection is closed, rather than when Content-Length bytes have been received. http://stackoverflow.com/q/34367115/1709587 describes this case in more detail.
Bizarrely,
header('http/1.1 200 OK');
does not have the same effect, despite producing a character-for-character identical HTTP response (as can be observed with `curl -i --raw`).
Test script:
---------------
<?php
header('HTTP/1.1 200 OK');
Expected result:
----------------
Unless `Connection: keep-alive` is specified in the request, the connection should close once the PHP script finishes. In particular, the behaviour should be identical to other calls with the same meaning, like
<?php
http_response_code(200);
or
<?php
header('http/1.1 200 OK')
Actual result:
--------------
The connection does not close, and the alternate scripts suggested above have different behaviours to the test script.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 09:00:02 2025 UTC |
> Unless `Connection: keep-alive` is specified in the request, the > connection should close once the PHP script finishes. For HTTP/1.1 requests, keep-alive is the default. Only HTTP/1.0 defaults to close.[1] > header('http/1.1 200 OK') This is not valid according to RFC 7230, since the HTTP-name needs to be upper case[2]. > http_response_code(200); I tentatively agree that this should behave identically to header('HTTP/1.1 200 OK'). I'll' have a closer look. [1] <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection> [2] <https://datatracker.ietf.org/doc/html/rfc7230#appendix-B>> > header('http/1.1 200 OK') > This is not valid according to RFC 7230, since the HTTP-name needs > to be upper case It's valid according to PHP's own docs at https://www.php.net/manual/en/function.header.php, which state that > There are two special-case header calls. The first is a header that starts with the string "HTTP/" (case is not significant) ... For whatever reason, the design decision has been made by PHP to let you pass such strings in lowercase and then convert them to uppercase for you to make them spec-compliant. The really mysterious thing is that invoking that case-conversion behaviour somehow prevents this bug from exhibiting.Anyway, I cannot reproduce any difference between the three scripts with PHP-7.4 on Windows using Apache 2.4.39.0. The response always has Connection: Keep-Alive Keep-Alive: timeout=5, max=100 and the connection is closed after ~ 5 seconds. If I add Connection: close to the request, the connection is immediately closed after the response has been received. So either the issue has been fixed in the meantime, or is specific to some Apache versions or the operating system. Can you still reproduce this with any of the actively supported PHP versions[1]? If so, what's your Apache version? [1] <https://www.php.net/supported-versions.php>I can reproduce on Ubuntu. I just tried installing PHP and Apache with sudo apt install php which gives me these versions: $ php --version PHP 7.4.3 (cli) (built: Oct 25 2021 18:20:54) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies $ apache2 -v Server version: Apache/2.4.41 (Ubuntu) Server built: 2021-10-14T16:24:43 If I create a test file containing <?php http_response_code(200); then ab takes 14ms per request: $ ab -n 1000 -c 200 localhost/marktest.php This is ApacheBench, Version 2.3 <$Revision: 1843412 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Completed 600 requests Completed 700 requests Completed 800 requests Completed 900 requests Completed 1000 requests Finished 1000 requests Server Software: Apache/2.4.41 Server Hostname: localhost Server Port: 80 Document Path: /marktest.php Document Length: 0 bytes Concurrency Level: 200 Time taken for tests: 0.070 seconds Complete requests: 1000 Failed requests: 0 Total transferred: 166000 bytes HTML transferred: 0 bytes Requests per second: 14259.44 [#/sec] (mean) Time per request: 14.026 [ms] (mean) Time per request: 0.070 [ms] (mean, across all concurrent requests) Transfer rate: 2311.59 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 5 1.0 5 7 Processing: 3 8 2.1 9 12 Waiting: 0 6 1.7 7 8 Total: 4 13 1.9 13 16 Percentage of the requests served within a certain time (ms) 50% 13 66% 14 75% 14 80% 14 90% 15 95% 15 98% 16 99% 16 100% 16 (longest request) but if I change it to call header('HTTP/1.1 200 OK'); instead, then it take 8 seconds per request: $ ab -n 1000 -c 200 localhost/marktest.php This is ApacheBench, Version 2.3 <$Revision: 1843412 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Completed 600 requests Completed 700 requests Completed 800 requests Completed 900 requests Completed 1000 requests Finished 1000 requests Server Software: Apache/2.4.41 Server Hostname: localhost Server Port: 80 Document Path: /marktest.php Document Length: 0 bytes Concurrency Level: 200 Time taken for tests: 41.478 seconds Complete requests: 1000 Failed requests: 0 Total transferred: 147000 bytes HTML transferred: 0 bytes Requests per second: 24.11 [#/sec] (mean) Time per request: 8295.664 [ms] (mean) Time per request: 41.478 [ms] (mean, across all concurrent requests) Transfer rate: 3.46 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 1 1.1 0 4 Processing: 5005 7684 2262.9 6939 15408 Waiting: 1 2680 2262.7 1935 10404 Total: 5006 7685 2263.6 6940 15410 Percentage of the requests served within a certain time (ms) 50% 6940 66% 7055 75% 7062 80% 8056 90% 11452 95% 13384 98% 14394 99% 15018 100% 15410 (longest request)