Skip to content

Commit

Permalink
Fix v4.4.x (#3612)
Browse files Browse the repository at this point in the history
* Fix #3362 (#3365)

* Fix #3368 (#3369)

* fix #3367

* Fix typo

Co-authored-by: twosee <twose@qq.com>

* Fix swoole_get_local_mac on OSX (#3372)

# Conflicts:
#	swoole.cc

* fix mysql test case (#3374)

* fix: stop worker in workerStart (#3382)

* fix: stop worker in workerStart

* improvement: add newline at end of file

* Fix missing MySQL transaction error, update the test (#3429)

* fix http client download filename bug (#3489)

* fix http client download filename bug

* fix zend::String()->release()

* Fix #3532 (#3534)

* fix #3532

* improve getHeaderOut()

* add tests
# Conflicts:
#	include/coroutine_socket.h
#	swoole_http_client_coro.cc

* Fixed: fix header inject when use CRLF (#3539)

* fix: fix header inject when use CRLF

* test: add test
# Conflicts:
#	swoole_http_response.cc

* Fixed: Fix  CRLF injection in `redirect` and `header` (#3541)

* Fix CRLF injection in `redirect` and `header`

The previous fix (#3539) was incomplete.
The added check is not enforced when `ucwords` is set to false.

* Fix typo
# Conflicts:
#	swoole_http_response.cc

* Fixed: check cookie injection (#3545)

* Fixed: check cookie injection

* fix: don't check crlf when use cookie urlencode
# Conflicts:
#	swoole_http_response.cc

* Fixed: set coroutine websocket server frame->fd (#3549)

* Fixed: set coroutine websocket server frame->fd

* fix: fix test

* Fix #3577 (#3579)

# Conflicts:
#	swoole_runtime.cc

* Fix the test (#3430)

# Conflicts:
#	tests/swoole_http2_client_coro/post.phpt

* test: fix swoole_http_client_coro/upload_big.phpt (#3590)

* fix: fix http client upload_big test

* fix: http client upload big file

* Fix test

* Fix free

* Fix free

Co-authored-by: twosee <twose@qq.com>
Co-authored-by: 韩天峰-Rango <mikan.tenny@gmail.com>
Co-authored-by: 耐小心 <qiqizjl@qq.com>
Co-authored-by: codinghuang <2812240764@qq.com>
Co-authored-by: Jiantao Li <CurseRed@Gmail.com>
  • Loading branch information
6 people committed Sep 1, 2020
1 parent 3190f71 commit 0c3b7e4
Show file tree
Hide file tree
Showing 27 changed files with 486 additions and 80 deletions.
18 changes: 18 additions & 0 deletions include/coroutine_socket.h
Expand Up @@ -326,6 +326,24 @@ class Socket
return write_buffer;
}

inline swString *pop_read_buffer() {
if (sw_unlikely(!read_buffer)) {
return nullptr;
}
auto tmp = read_buffer;
read_buffer = nullptr;
return tmp;
}

inline swString *pop_write_buffer() {
if (sw_unlikely(!write_buffer)) {
return nullptr;
}
auto tmp = write_buffer;
write_buffer = nullptr;
return tmp;
}

#ifdef SW_USE_OPENSSL
inline bool is_ssl_enable()
{
Expand Down
5 changes: 2 additions & 3 deletions php_swoole.h
Expand Up @@ -92,9 +92,8 @@ extern zend_module_entry swoole_module_entry;
# define PHP_SWOOLE_API
#endif

#ifdef __APPLE__
#define SIOCGIFHWADDR SIOCGIFCONF
#define ifr_hwaddr ifr_addr
#if __MACH__
#include <net/if_dl.h>
#endif

#define SW_CHECK_RETURN(s) if(s<0){RETURN_FALSE;}else{RETURN_TRUE;}
Expand Down
1 change: 1 addition & 0 deletions php_swoole_cxx.h
Expand Up @@ -112,6 +112,7 @@ class string
if (str)
{
zend_string_release(str);
str = nullptr;
}
}

Expand Down
34 changes: 24 additions & 10 deletions swoole.cc
Expand Up @@ -884,10 +884,15 @@ PHP_FUNCTION(swoole_get_local_ip)

PHP_FUNCTION(swoole_get_local_mac)
{
auto add_assoc_address = [](zval *zv, const char *name, const unsigned char *addr)
{
char buf[32];
sw_snprintf(SW_STRS(buf), "%02X:%02X:%02X:%02X:%02X:%02X", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
add_assoc_string(zv, name, buf);
};
#ifdef SIOCGIFHWADDR
struct ifconf ifc;
struct ifreq buf[16];
char mac[32] = {};

int sock;
int i = 0,num = 0;
Expand All @@ -908,23 +913,32 @@ PHP_FUNCTION(swoole_get_local_mac)
{
if (!(ioctl(sock, SIOCGIFHWADDR, (char *) &buf[i])))
{
sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
(unsigned char) buf[i].ifr_hwaddr.sa_data[0],
(unsigned char) buf[i].ifr_hwaddr.sa_data[1],
(unsigned char) buf[i].ifr_hwaddr.sa_data[2],
(unsigned char) buf[i].ifr_hwaddr.sa_data[3],
(unsigned char) buf[i].ifr_hwaddr.sa_data[4],
(unsigned char) buf[i].ifr_hwaddr.sa_data[5]);
add_assoc_string(return_value, buf[i].ifr_name, mac);
add_assoc_address(return_value, buf[i].ifr_name, (unsigned char *) buf[i].ifr_hwaddr.sa_data);
}
i++;
}
}
close(sock);
#else
php_error_docref(NULL, E_WARNING, "swoole_get_local_mac is not supported");
#ifdef LLADDR
ifaddrs* ifas, *ifa;
if (getifaddrs(&ifas) == 0)
{
array_init(return_value);
for (ifa = ifas; ifa; ifa = ifa->ifa_next)
{
if ((ifa->ifa_addr->sa_family == AF_LINK) && ifa->ifa_addr)
{
add_assoc_address(return_value, ifa->ifa_name, (unsigned char *) (LLADDR((struct sockaddr_dl *) ifa->ifa_addr)));
}
}
freeifaddrs(ifas);
}
#else
php_error_docref(nullptr, E_WARNING, "swoole_get_local_mac is not supported");
RETURN_FALSE;
#endif
#endif
}

PHP_FUNCTION(swoole_internal_call_user_shutdown_begin)
Expand Down
18 changes: 17 additions & 1 deletion swoole_http_client_coro.cc
Expand Up @@ -94,6 +94,7 @@ class http_client
/* safety zval */
zval _zobject;
zval *zobject = &_zobject;
swString *tmp_write_buffer = nullptr;

http_client(zval* zobject, std::string host, zend_long port = 80, zend_bool ssl = false);

Expand Down Expand Up @@ -126,7 +127,15 @@ class http_client

void get_header_out(zval *return_value)
{
swString *buffer = socket->get_write_buffer();
swString *buffer = nullptr;
if (socket == nullptr) {
if (tmp_write_buffer) {
buffer = tmp_write_buffer;
}
}
else {
buffer = socket->get_write_buffer();
}
if (buffer == nullptr)
{
RETURN_FALSE;
Expand Down Expand Up @@ -1656,6 +1665,10 @@ bool http_client::close(const bool should_be_reset)
#ifdef SW_HAVE_ZLIB
websocket_compression = false;
#endif
if (tmp_write_buffer) {
swString_free(tmp_write_buffer);
}
tmp_write_buffer = socket->pop_write_buffer();
socket = nullptr;
}
php_swoole_client_coro_socket_free(_socket);
Expand All @@ -1671,6 +1684,9 @@ http_client::~http_client()
{
swString_free(body);
}
if (tmp_write_buffer) {
swString_free(tmp_write_buffer);
}
}

static sw_inline http_client_coro* php_swoole_http_client_coro_fetch_object(zend_object *obj)
Expand Down
27 changes: 27 additions & 0 deletions swoole_http_response.cc
Expand Up @@ -81,6 +81,23 @@ static inline void http_header_key_format(char *key, int length)
}
}

static inline bool http_has_crlf(const char *value, int length) {
/* new line/NUL character safety check */
for (uint32_t i = 0; i < length; i++) {
/* RFC 7230 ch. 3.2.4 deprecates folding support */
if (value[i] == '\n' || value[i] == '\r') {
php_swoole_error(E_WARNING, "Header may not contain more than a single header, new line detected");
return true;
}
if (value[i] == '\0') {
php_swoole_error(E_WARNING, "Header may not contain NUL bytes");
return true;
}
}

return false;
}

static inline swString* http_get_write_buffer(http_context *ctx)
{
if (ctx->co_socket)
Expand Down Expand Up @@ -861,6 +878,10 @@ bool swoole_http_response_set_header(http_context *ctx, const char *k, size_t kl
php_swoole_error(E_WARNING, "header key is too long");
return false;
}

if (http_has_crlf(v, vlen)) {
return false;
}
zval *zheader = swoole_http_init_and_read_property(swoole_http_response_ce, ctx->response.zobject, &ctx->response.zheader, ZEND_STRL("header"));
if (ucwords)
{
Expand Down Expand Up @@ -1036,6 +1057,11 @@ static void php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAMETERS, const
php_swoole_error(E_WARNING, "Cookie names can't contain any of the following '=,; \\t\\r\\n\\013\\014'");
RETURN_FALSE;
}

if (!url_encode && http_has_crlf(value, value_len)) {
RETURN_FALSE;
}

if (value_len == 0)
{
cookie = (char *) emalloc(cookie_size);
Expand Down Expand Up @@ -1335,6 +1361,7 @@ static PHP_METHOD(swoole_http_response, recv)
#else
php_swoole_websocket_frame_unpack(&_tmp, return_value);
#endif
zend_update_property_long(swoole_websocket_frame_ce, return_value, ZEND_STRL("fd"), sock->get_fd());
}
}

Expand Down
1 change: 1 addition & 0 deletions swoole_mysql_coro.cc
Expand Up @@ -2332,6 +2332,7 @@ static void swoole_mysql_coro_query_transcation(INTERNAL_FUNCTION_PARAMETERS, co
mc->add_timeout_controller(timeout, SW_TIMEOUT_RDWR);
mc->query(return_value, command, command_length);
mc->del_timeout_controller();
swoole_mysql_coro_sync_query_result_properties(ZEND_THIS, mc, return_value);
}

static PHP_METHOD(swoole_mysql_coro, begin)
Expand Down
10 changes: 2 additions & 8 deletions swoole_redis_server.cc
Expand Up @@ -30,7 +30,6 @@ using namespace std;
static zend_class_entry *swoole_redis_server_ce;
static zend_object_handlers swoole_redis_server_handlers;

static swString *format_buffer;
static unordered_map<string, zend_fcall_info_cache> redis_handlers;

static PHP_METHOD(swoole_redis_server, start);
Expand Down Expand Up @@ -234,13 +233,6 @@ static PHP_METHOD(swoole_redis_server, start)

serv->onReceive = redis_onReceive;

format_buffer = swString_new(SW_BUFFER_SIZE_STD);
if (!format_buffer)
{
php_swoole_fatal_error(E_ERROR, "[1] swString_new(%d) failed", SW_BUFFER_SIZE_STD);
RETURN_FALSE;
}

zval *zsetting = sw_zend_read_and_convert_property_array(swoole_server_ce, zserv, ZEND_STRL("setting"), 0);

add_assoc_bool(zsetting, "open_http_protocol", 0);
Expand Down Expand Up @@ -343,6 +335,8 @@ static PHP_METHOD(swoole_redis_server, format)
int length;
zval *item;

swString *format_buffer = SwooleTG.buffer_stack;

if (type == SW_REDIS_REPLY_NIL)
{
RETURN_STRINGL(SW_REDIS_RETURN_NIL, sizeof(SW_REDIS_RETURN_NIL)-1);
Expand Down
15 changes: 0 additions & 15 deletions swoole_runtime.cc
Expand Up @@ -1008,21 +1008,6 @@ static php_stream *socket_create(
abstract->socket = sock;
abstract->stream.socket = sock->get_fd();

if (timeout)
{
sock->set_timeout(timeout);
abstract->stream.timeout = *timeout;
}
else if (FG(default_socket_timeout) > 0)
{
sock->set_timeout((double) FG(default_socket_timeout));
abstract->stream.timeout.tv_sec = FG(default_socket_timeout);
}
else
{
sock->set_timeout(-1);
abstract->stream.timeout.tv_sec = -1;
}

persistent_id = nullptr;//prevent stream api in user level using pconnect to persist the socket
stream = php_stream_alloc_rel(&socket_ops, abstract, persistent_id, "r+");
Expand Down
10 changes: 7 additions & 3 deletions swoole_server.cc
Expand Up @@ -1968,8 +1968,8 @@ static int php_swoole_server_dispatch_func(swServer *serv, swConnection *conn, s

*zserv = *((zval *) serv->ptr2);
ZVAL_LONG(zfd, (zend_long) (conn ? conn->session_id : data->info.fd));
ZVAL_LONG(ztype, (zend_long) data->info.type);
if (sw_zend_function_max_num_args(fci_cache->function_handler) > 3)
ZVAL_LONG(ztype, (zend_long) (data ? data->info.type : SW_SERVER_EVENT_CLOSE));
if (data && sw_zend_function_max_num_args(fci_cache->function_handler) > 3)
{
// TODO: reduce memory copy
zdata = &args[3];
Expand Down Expand Up @@ -4228,8 +4228,12 @@ static PHP_METHOD(swoole_server, stop)
{
if (SwooleTG.reactor != NULL)
{
SwooleTG.reactor->running = 0;
SwooleTG.reactor->defer(SwooleTG.reactor, [](void *data) {
swReactor *reactor = (swReactor *) data;
reactor->running = 0;
}, SwooleTG.reactor);
}

SwooleG.running = 0;
}
else
Expand Down
3 changes: 2 additions & 1 deletion tests/swoole_event/add_after_server_start.phpt
Expand Up @@ -15,7 +15,8 @@ const FILE = __DIR__.'/tmp_result.txt';
$pm = new SwooleTest\ProcessManager;
$pm->parentFunc = function ($pid) use ($pm) {
$pm->kill();
Assert::contains(file_get_contents(FILE), 'HTTP/1.1 302 Moved Temporarily');
$str = swoole_string(file_get_contents(FILE));
Assert::true($str->contains('HTTP/1.1 302 Moved Temporarily') or $str->contains('HTTP/1.1 301 Moved Permanently'));
};

$pm->childFunc = function () use ($pm) {
Expand Down
3 changes: 2 additions & 1 deletion tests/swoole_http2_client_coro/post.phpt
Expand Up @@ -29,7 +29,8 @@ go(function () {
$req->data = '{"type":"up"}';
$cli->send($req);
$response = $cli->recv();
Assert::same(json_decode($response->data)->error->code, 602);
Assert::true(in_array(json_decode($response->data)->error->code, [602, 10002], true));
});
?>
--EXPECT--

74 changes: 74 additions & 0 deletions tests/swoole_http_client_coro/download_filename_bug.phpt
@@ -0,0 +1,74 @@
--TEST--
swoole_http_client_coro: The bug of the filename parameter of download()
--SKIPIF--
<?php
require __DIR__ . '/../include/skipif.inc';
?>
--FILE--
<?php
require __DIR__ . '/../include/bootstrap.php';
class C1
{
protected $f;

protected $savedFileName;

public function __construct($f)
{
$this->f = $f;
}

public function withSavedFileName($savedFileName)
{
$self = clone $this;
$self->savedFileName = $savedFileName;
return $self;
}

public function getSavedFileName()
{
return $this->savedFileName;
}

}

function download($pm, $fileName)
{
$basename = substr($fileName, 0, -2);
$fileName = $basename . '.jpg';
$c1 = new C1($fileName);
$c1 = $c1->withSavedFileName($fileName);

$client = new \Swoole\Coroutine\Http\Client('127.0.0.1', $pm->getFreePort());
$client->set(['timeout' => 5]);

$client->download('/', $fileName);
}

$pm = new SwooleTest\ProcessManager;
$pm->parentFunc = function () use ($pm) {
Co\run(function () use($pm) {
download($pm, '/tmp/test-1.*');
});

Co\run(function () use($pm) {
download($pm, '/tmp/test-2.*');
});

$pm->kill();
};
$pm->childFunc = function () use ($pm) {
$serv = new swoole_http_server('127.0.0.1', $pm->getFreePort(), SERVER_MODE_RANDOM);
$serv->set(['log_file' => '/dev/null']);
$serv->on('workerStart', function () use ($pm) {
$pm->wakeup();
});
$serv->on('request', function (swoole_http_request $request, swoole_http_response $response) {
$response->sendfile(TEST_IMAGE);
});
$serv->start();
};
$pm->childFirst();
$pm->run();
?>
--EXPECT--

0 comments on commit 0c3b7e4

Please sign in to comment.