Change the search in get_status_string() to correctly handle unknown codes.

This previously used a buggy implementation of binary search that would loop
infinitely for unknown codes when searching in reason arrays of particular
sizes (such as the one we have at the moment). Since C provides bsearch(),
we'll just use that instead, since libc authors hopefully get this right.

There was also an additional bug that was masked by the first one: the design
was that an unknown code would result in get_status_string() returning NULL,
which would then result in a segfault in append_http_status_line(), since it
assumed that it would always receive a valid string pointer that could be
handed off to smart_str_appends_ex(). We'll now return a placeholder in that
case.

Fixes bug #65066 (Cli server not responsive when responding with 422 http
status code).
This commit is contained in:
Adam Harvey 2013-06-19 11:32:37 -07:00
parent b5978e239e
commit 283f56af66
5 changed files with 150 additions and 13 deletions

4
NEWS
View File

@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2013, PHP 5.4.18
- CLI server:
. Fixed bug #65066 (Cli server not responsive when responding with 422 http
status code). (Adam)
?? ??? 2013, PHP 5.4.17
- Core:

View File

@ -20,6 +20,7 @@
/* $Id: php_cli.c 306938 2011-01-01 02:17:06Z felipe $ */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
@ -333,23 +334,38 @@ static char *get_last_error() /* {{{ */
return pestrdup(strerror(errno), 1);
} /* }}} */
static int status_comp(const void *a, const void *b) /* {{{ */
{
const php_cli_server_http_reponse_status_code_pair *pa = (const php_cli_server_http_reponse_status_code_pair *) a;
const php_cli_server_http_reponse_status_code_pair *pb = (const php_cli_server_http_reponse_status_code_pair *) b;
if (pa->code < pb->code) {
return -1;
} else if (pa->code > pb->code) {
return 1;
}
return 0;
} /* }}} */
static const char *get_status_string(int code) /* {{{ */
{
size_t e = (sizeof(status_map) / sizeof(php_cli_server_http_reponse_status_code_pair));
size_t s = 0;
php_cli_server_http_reponse_status_code_pair needle, *result = NULL;
while (e != s) {
size_t c = MIN((e + s + 1) / 2, e - 1);
int d = status_map[c].code;
if (d > code) {
e = c;
} else if (d < code) {
s = c;
} else {
return status_map[c].str;
needle.code = code;
needle.str = NULL;
result = bsearch(&needle, status_map, sizeof(status_map) / sizeof(needle), sizeof(needle), status_comp);
if (result) {
return result->str;
}
}
return NULL;
/* Returning NULL would require complicating append_http_status_line() to
* not segfault in that case, so let's just return a placeholder, since RFC
* 2616 requires a reason phrase. This is basically what a lot of other Web
* servers do in this case anyway. */
return "Unknown Status Code";
} /* }}} */
static const char *get_template_string(int code) /* {{{ */

View File

@ -0,0 +1,39 @@
--TEST--
Bug #65066 (Cli server not responsive when responding with 422 http status code): 100 status code
--INI--
allow_url_fopen=1
--SKIPIF--
<?php
include "skipif.inc";
?>
--FILE--
<?php
include "php_cli_server.inc";
php_cli_server_start('http_response_code(100);');
list($host, $port) = explode(':', PHP_CLI_SERVER_ADDRESS);
$port = intval($port)?:80;
$fp = fsockopen($host, $port, $errno, $errstr, 0.5);
if (!$fp) {
die("connect failed");
}
if(fwrite($fp, <<<HEADER
GET / HTTP/1.1
Host: {$host}
HEADER
)) {
while (!feof($fp)) {
echo fgets($fp);
}
}
?>
--EXPECTF--
HTTP/1.1 100 Continue
Host: %s
Connection: close
X-Powered-By: PHP/%s
Content-type: text/html

View File

@ -0,0 +1,39 @@
--TEST--
Bug #65066 (Cli server not responsive when responding with 422 http status code): 422 status code
--INI--
allow_url_fopen=1
--SKIPIF--
<?php
include "skipif.inc";
?>
--FILE--
<?php
include "php_cli_server.inc";
php_cli_server_start('http_response_code(422);');
list($host, $port) = explode(':', PHP_CLI_SERVER_ADDRESS);
$port = intval($port)?:80;
$fp = fsockopen($host, $port, $errno, $errstr, 0.5);
if (!$fp) {
die("connect failed");
}
if(fwrite($fp, <<<HEADER
GET / HTTP/1.1
Host: {$host}
HEADER
)) {
while (!feof($fp)) {
echo fgets($fp);
}
}
?>
--EXPECTF--
HTTP/1.1 422 Unknown Status Code
Host: %s
Connection: close
X-Powered-By: PHP/%s
Content-type: text/html

View File

@ -0,0 +1,39 @@
--TEST--
Bug #65066 (Cli server not responsive when responding with 422 http status code): 511 status code
--INI--
allow_url_fopen=1
--SKIPIF--
<?php
include "skipif.inc";
?>
--FILE--
<?php
include "php_cli_server.inc";
php_cli_server_start('http_response_code(511);');
list($host, $port) = explode(':', PHP_CLI_SERVER_ADDRESS);
$port = intval($port)?:80;
$fp = fsockopen($host, $port, $errno, $errstr, 0.5);
if (!$fp) {
die("connect failed");
}
if(fwrite($fp, <<<HEADER
GET / HTTP/1.1
Host: {$host}
HEADER
)) {
while (!feof($fp)) {
echo fgets($fp);
}
}
?>
--EXPECTF--
HTTP/1.1 511 Network Authentication Required
Host: %s
Connection: close
X-Powered-By: PHP/%s
Content-type: text/html