Skip to content

Commit

Permalink
Fix max_input_vars limit error (#5266)
Browse files Browse the repository at this point in the history
* Fix max_input_vars error

* Copyright Protection

* remove header file
  • Loading branch information
NathanFreeman authored Mar 6, 2024
1 parent 3eab031 commit 1a61ad0
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 21 deletions.
28 changes: 7 additions & 21 deletions ext-src/swoole_http_request.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
SW_EXTERN_C_BEGIN
#include "ext/standard/url.h"
#include "stubs/php_swoole_http_request_arginfo.h"
#include "thirdparty/php/main/SAPI.h"
SW_EXTERN_C_END

#include "main/php_variables.h"

#ifdef SW_HAVE_ZLIB
#include <zlib.h>
#endif
Expand Down Expand Up @@ -258,7 +257,7 @@ static int http_request_on_query_string(swoole_http_parser *parser, const char *
http_server_add_server_array(ht, SW_ZSTR_KNOWN(SW_ZEND_STR_QUERY_STRING), &tmp);

// parse url params
sapi_module.treat_data(
swoole_php_treat_data(
PARSE_STRING,
estrndup(at, length), // it will be freed by treat_data
swoole_http_init_and_read_property(
Expand Down Expand Up @@ -295,25 +294,12 @@ bool HttpContext::get_multipart_boundary(
return true;
}

void swoole_http_parse_cookie(zval *zarray, const char *at, size_t length) {
void swoole_http_parse_cookie(zval *zcookies, const char *at, size_t length) {
if (length == 0) {
return;
}
zend_long count = 0;
ParseCookieCallback cb = [&count, zarray](char *key, size_t key_len, char *value, size_t value_len) {
if (++count > PG(max_input_vars)) {
swoole_warning("Input variables exceeded " ZEND_LONG_FMT
". To increase the limit change max_input_vars in php.ini.",
PG(max_input_vars));
return false;
}
if (value_len > 0) {
value_len = php_raw_url_decode(value, value_len);
}
add_assoc_stringl_ex(zarray, key, key_len, value, value_len);
return true;
};
swoole::http_server::parse_cookie(at, length, cb);

swoole_php_treat_data(PARSE_COOKIE, estrndup(at, length), zcookies);
}

static void http_request_add_upload_file(HttpContext *ctx, const char *file, size_t l_file) {
Expand Down Expand Up @@ -793,13 +779,13 @@ static int http_request_message_complete(swoole_http_parser *parser) {

if (ctx->request.chunked_body != nullptr && ctx->parse_body && ctx->request.post_form_urlencoded) {
/* parse dechunked content */
sapi_module.treat_data(
swoole_php_treat_data(
PARSE_STRING,
estrndup(ctx->request.chunked_body->str, content_length), // do not free, it will be freed by treat_data
swoole_http_init_and_read_property(
swoole_http_request_ce, ctx->request.zobject, &ctx->request.zpost, SW_ZSTR_KNOWN(SW_ZEND_STR_POST)));
} else if (!ctx->recv_chunked && ctx->parse_body && ctx->request.post_form_urlencoded && ctx->request.body_at) {
sapi_module.treat_data(
swoole_php_treat_data(
PARSE_STRING,
estrndup(ctx->request.body_at, ctx->request.body_length), // do not free, it will be freed by treat_data
swoole_http_init_and_read_property(
Expand Down
67 changes: 67 additions & 0 deletions tests/swoole_http_server/max_input_vars.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
--TEST--
swoole_http_server: max_input_vars
--SKIPIF--
<?php require __DIR__ . '/../include/skipif.inc'; ?>
--FILE--
<?php
require __DIR__ . '/../include/bootstrap.php';

use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;

$pm = new SwooleTest\ProcessManager;
$pm->parentFunc = function () use ($pm) {
Swoole\Coroutine\run(function () use ($pm) {
$maxInputVars = ini_get('max_input_vars') + 10;
$data = [];
$cookies = [];
$temp = 'max_input_vars';
for ($i = 0; $i < $maxInputVars; $i++) {
$data[$temp . $i] = $temp;
$cookies[] = $temp . $i.'='.$temp;
}

// post method
httpRequest("http://127.0.0.1:{$pm->getFreePort()}", ['data' => $data, 'headers' => ['Cookie' => implode(';', $cookies)]]);

// get method
httpRequest("http://127.0.0.1:{$pm->getFreePort()}?".http_build_query($data));
});
echo "DONE\n";
$pm->kill();
};

$pm->childFunc = function () use ($pm) {
$http = new Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
$http->on('workerStart', function () use ($pm) {
$pm->wakeup();
});
$http->on('request', function (Request $request, Response $response){
$maxInputVars = ini_get('max_input_vars');
if ($request->get) {
var_dump(count($request->get) == $maxInputVars);
}

if ($request->post) {
var_dump(count($request->post) == $maxInputVars);
}

if ($request->cookie) {
var_dump(count($request->cookie) == $maxInputVars);
}
$response->end();
});
$http->start();
};
$pm->childFirst();
$pm->run();
?>
--EXPECTF--
%s To increase the limit change max_input_vars in php.ini.
%s To increase the limit change max_input_vars in php.ini.
bool(true)
bool(true)
%s To increase the limit change max_input_vars in php.ini.
bool(true)
DONE
105 changes: 105 additions & 0 deletions thirdparty/php/main/SAPI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| [email protected] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Zeev Suraski <[email protected]> |
+----------------------------------------------------------------------+
*/

#include "main/php_variables.h"

/**
* This only handles the cases of PARSE_STRING and PARSE_COOKIE
*/
static void swoole_php_treat_data(int arg, char *str, zval *destArray) {
char *res = NULL, *var, *val, *separator = NULL;
zval array;
int free_buffer = 0;
char *strtok_buf = NULL;
zend_long count = 0;

ZVAL_UNDEF(&array);
ZVAL_COPY_VALUE(&array, destArray);

res = str;
free_buffer = 1;

if (!res) {
return;
}

switch (arg) {
case PARSE_STRING:
separator = PG(arg_separator).input;
break;
case PARSE_COOKIE:
separator = (char *) ";\0";
break;
}

var = php_strtok_r(res, separator, &strtok_buf);

while (var) {
size_t val_len;
size_t new_val_len;

val = strchr(var, '=');

if (arg == PARSE_COOKIE) {
/* Remove leading spaces from cookie names, needed for multi-cookie header where ; can be followed by a
* space */
while (isspace(*var)) {
var++;
}
if (var == val || *var == '\0') {
goto next_cookie;
}
}

if (++count > PG(max_input_vars)) {
swoole_warning("Input variables exceeded " ZEND_LONG_FMT
". To increase the limit change max_input_vars in php.ini.",
PG(max_input_vars));
break;
}

if (val) { /* have a value */
*val++ = '\0';
if (arg == PARSE_COOKIE) {
val_len = php_raw_url_decode(val, strlen(val));
} else {
val_len = php_url_decode(val, strlen(val));
}
} else {
val = (char *) "";
val_len = 0;
}

val = estrndup(val, val_len);
if (arg != PARSE_COOKIE) {
php_url_decode(var, strlen(var));
}

if (sapi_module.input_filter(PARSE_STRING, var, &val, val_len, &new_val_len)) {
if (arg == PARSE_STRING ||
(arg == PARSE_COOKIE && !zend_symtable_str_exists(Z_ARRVAL_P(&array), var, strlen(var)))) {
php_register_variable_safe(var, val, new_val_len, &array);
}
}
efree(val);
next_cookie:
var = php_strtok_r(NULL, separator, &strtok_buf);
}

if (free_buffer) {
efree(res);
}
}

0 comments on commit 1a61ad0

Please sign in to comment.