Skip to content

Commit 6744494

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 6acdef4 + 3d2356f commit 6744494

8 files changed

+218
-50
lines changed

swoole_http_client_coro.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -1440,10 +1440,10 @@ bool http_client::recv_http_response(double timeout)
14401440
swTraceLog(SW_TRACE_HTTP_CLIENT, "parsed_n=%ld, retval=%ld, total_bytes=%ld, completed=%d", parsed_n, retval, total_bytes, parser.state == s_start_res);
14411441
if (parser.state == s_start_res)
14421442
{
1443-
// websocket stick package
1444-
if (parser.upgrade && (size_t) retval > parsed_n + 1 + SW_WEBSOCKET_HEADER_LEN)
1443+
// handle redundant data (websocket packet)
1444+
if (parser.upgrade && (size_t) retval > parsed_n + SW_WEBSOCKET_HEADER_LEN)
14451445
{
1446-
swString_sub(buffer, parsed_n + 1, retval - parsed_n - 1);
1446+
swString_sub(buffer, parsed_n, retval - parsed_n);
14471447
}
14481448
return true;
14491449
}

swoole_http_request.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ static int http_request_message_complete(swoole_http_parser *parser)
902902
}
903903
ctx->completed = 1;
904904

905-
return 0;
905+
return 1; /* return from execute */
906906
}
907907

908908
#ifdef SW_HAVE_COMPRESSION

swoole_http_server.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ int php_swoole_http_onReceive(swServer *serv, swEventData *req)
8888
swoole_http_parser_init(parser, PHP_HTTP_REQUEST);
8989

9090
size_t parsed_n = swoole_http_requset_parse(ctx, Z_STRVAL_P(zdata), Z_STRLEN_P(zdata));
91-
if (parsed_n < Z_STRLEN_P(zdata))
91+
if (ctx->parser.state == s_dead)
9292
{
9393
#ifdef SW_HTTP_BAD_REQUEST_PACKET
9494
ctx->send(ctx, SW_STRL(SW_HTTP_BAD_REQUEST_PACKET));

swoole_http_server_coro.cc

+62-38
Original file line numberDiff line numberDiff line change
@@ -503,43 +503,61 @@ static PHP_METHOD(swoole_http_server_coro, onAccept)
503503

504504
while (true)
505505
{
506-
hs->receivers.push_front(sock);
507-
auto receiver = hs->receivers.begin();
508-
ssize_t retval = sock->recv(buffer->str + total_bytes + buffer->offset, buffer->size - total_bytes - buffer->offset);
509-
hs->receivers.erase(receiver);
510-
511-
if (sw_unlikely(retval <= 0))
506+
ssize_t retval;
507+
if (ctx != nullptr || total_bytes == 0)
512508
{
513-
break;
514-
}
515-
total_bytes += retval;
509+
hs->receivers.push_front(sock);
510+
auto receiver = hs->receivers.begin();
511+
retval = sock->recv(buffer->str + total_bytes, buffer->size - total_bytes);
512+
hs->receivers.erase(receiver);
516513

517-
if (!ctx)
518-
{
519-
ctx = hs->create_context(sock, zconn);
520-
}
514+
if (sw_unlikely(retval <= 0))
515+
{
516+
break;
517+
}
521518

522-
if (total_bytes > sock->protocol.package_max_length)
519+
if (!ctx)
520+
{
521+
ctx = hs->create_context(sock, zconn);
522+
}
523+
524+
if (total_bytes + retval > sock->protocol.package_max_length)
525+
{
526+
ctx->response.status = SW_HTTP_REQUEST_ENTITY_TOO_LARGE;
527+
break;
528+
}
529+
}
530+
else
523531
{
524-
ctx->response.status = 413;
525-
_error:
526-
zval_dtor(ctx->request.zobject);
527-
zval_dtor(ctx->response.zobject);
528-
break;
532+
/* redundant data from previous packet */
533+
retval = total_bytes;
534+
total_bytes = 0;
535+
536+
if (!ctx)
537+
{
538+
ctx = hs->create_context(sock, zconn);
539+
}
529540
}
530541

531-
size_t parsed_n = swoole_http_requset_parse(ctx, buffer->str + total_bytes - retval, retval);
542+
size_t parsed_n = swoole_http_requset_parse(ctx, buffer->str + total_bytes, retval);
543+
size_t total_parsed_n = total_bytes + parsed_n;
544+
total_bytes += retval;
532545

533546
swTraceLog(SW_TRACE_CO_HTTP_SERVER, "parsed_n=%ld, retval=%ld, total_bytes=%ld, completed=%d", parsed_n, retval, total_bytes, ctx->completed);
534547

535548
if (!ctx->completed)
536549
{
550+
if (ctx->parser.state == s_dead)
551+
{
552+
ctx->response.status = SW_HTTP_BAD_REQUEST;
553+
break;
554+
}
537555
if (total_bytes == buffer->size)
538556
{
539557
if (swString_extend(buffer, buffer->size * 2) != SW_OK)
540558
{
541-
ctx->response.status = 503;
542-
goto _error;
559+
ctx->response.status = SW_HTTP_SERVICE_UNAVAILABLE;
560+
break;
543561
}
544562
}
545563
continue;
@@ -549,26 +567,31 @@ static PHP_METHOD(swoole_http_server_coro, onAccept)
549567
if (ctx->parser.method == PHP_HTTP_NOT_IMPLEMENTED
550568
&& memcmp(buffer->str, SW_HTTP2_PRI_STRING, sizeof(SW_HTTP2_PRI_STRING) - 1) == 0)
551569
{
552-
buffer->length = retval - (sizeof(SW_HTTP2_PRI_STRING) - 1);
553-
buffer->offset = buffer->length == 0 ? 0 : parsed_n;
570+
buffer->length = total_bytes - (sizeof(SW_HTTP2_PRI_STRING) - 1);
571+
buffer->offset = buffer->length == 0 ? 0 : (sizeof(SW_HTTP2_PRI_STRING) - 1);
554572
hs->recv_http2_frame(ctx);
555573
break;
556574
}
557575
#endif
558576

559-
if (retval > (ssize_t) parsed_n)
577+
ZVAL_STRINGL(&ctx->request.zdata, buffer->str, total_parsed_n);
578+
579+
/* handle more packages */
580+
if ((size_t) retval > parsed_n)
560581
{
561-
buffer->offset = retval - parsed_n;
562-
memmove(buffer->str, buffer->str + total_bytes + parsed_n, buffer->offset);
582+
total_bytes = retval - parsed_n;
583+
memmove(buffer->str, buffer->str + total_parsed_n, total_bytes);
584+
if (ctx->websocket)
585+
{
586+
/* for recv_packet */
587+
buffer->length = total_bytes;
588+
}
563589
}
564590
else
565591
{
566-
buffer->offset = 0;
592+
total_bytes = 0;
567593
}
568594

569-
ZVAL_STRINGL(&ctx->request.zdata, buffer->str, total_bytes);
570-
total_bytes = 0;
571-
572595
zval *zserver = ctx->request.zserver;
573596
add_assoc_long(zserver, "server_port", hs->socket->get_bind_port());
574597
add_assoc_long(zserver, "remote_port", (zend_long) hs->socket->get_port());
@@ -595,18 +618,19 @@ static PHP_METHOD(swoole_http_server_coro, onAccept)
595618

596619
zval_dtor(&args[0]);
597620
zval_dtor(&args[1]);
621+
ctx = nullptr;
598622

599-
if (hs->running && keep_alive)
600-
{
601-
swTraceLog(SW_TRACE_CO_HTTP_SERVER, "http_server_coro keepalive");
602-
ctx = nullptr;
603-
continue;
604-
}
605-
else
623+
if (!hs->running || !keep_alive)
606624
{
607625
break;
608626
}
609627
}
628+
629+
if (ctx)
630+
{
631+
zval_dtor(ctx->request.zobject);
632+
zval_dtor(ctx->response.zobject);
633+
}
610634
}
611635

612636
static PHP_METHOD(swoole_http_server_coro, shutdown)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
swoole_http_server_coro: bad request
3+
--SKIPIF--
4+
<?php require __DIR__ . '/../include/skipif.inc'; ?>
5+
--FILE--
6+
<?php
7+
require __DIR__ . '/../include/bootstrap.php';
8+
9+
use Swoole\Coroutine;
10+
use Swoole\Coroutine\Http\Server;
11+
use Swoole\Coroutine\Socket;
12+
use Swoole\Http\Request;
13+
use Swoole\Http\Response;
14+
15+
const REQUEST = "GET / HTTP/1.1\r\nContent-Length: invalid\r\n\r\n";
16+
17+
Coroutine\run(function () {
18+
$server = new Server('127.0.0.1', 0);
19+
Coroutine::create(function () use ($server) {
20+
$server->handle('/', function (Request $request, Response $response) use ($server) {
21+
echo "never here\n";
22+
});
23+
$server->start();
24+
});
25+
Coroutine::sleep(0.001);
26+
Coroutine::create(function () use ($server) {
27+
$socket = new Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
28+
if (Assert::true($socket->connect('127.0.0.1', $server->port, -1))) {
29+
$ret = $socket->sendAll(REQUEST);
30+
Assert::same($ret, strlen(REQUEST));
31+
Assert::contains($socket->recv(), 'HTTP/1.1 400 Bad Request');
32+
$server->shutdown();
33+
echo "DONE\n";
34+
}
35+
});
36+
});
37+
38+
?>
39+
--EXPECT--
40+
DONE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
--TEST--
2+
swoole_http_server_coro: pipeline
3+
--SKIPIF--
4+
<?php require __DIR__ . '/../include/skipif.inc'; ?>
5+
--FILE--
6+
<?php
7+
require __DIR__ . '/../include/bootstrap.php';
8+
9+
use Swoole\Coroutine;
10+
use Swoole\Coroutine\Http\Server;
11+
use Swoole\Coroutine\Socket;
12+
use Swoole\Http\Request;
13+
use Swoole\Http\Response;
14+
15+
const REQUEST = "GET / HTTP/1.1\r\n\r\n";
16+
17+
Coroutine\run(function () {
18+
$server = new Server('127.0.0.1', 0);
19+
Coroutine::create(function () use ($server) {
20+
$server->handle('/', function (Request $request, Response $response) use ($server) {
21+
static $count = 0;
22+
if (++$count === MAX_CONCURRENCY * MAX_REQUESTS) {
23+
echo "DONE\n";
24+
$server->shutdown();
25+
}
26+
});
27+
$server->start();
28+
});
29+
for ($c = MAX_CONCURRENCY; $c--;) {
30+
Coroutine::sleep(0.001);
31+
Coroutine::create(function () use ($server) {
32+
$socket = new Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
33+
if (Assert::true($socket->connect('127.0.0.1', $server->port, -1))) {
34+
$ret = $socket->sendAll(str_repeat(REQUEST, MAX_REQUESTS));
35+
Assert::same($ret, strlen(REQUEST) * MAX_REQUESTS);
36+
} else {
37+
throw new RuntimeException('Connect failed: ' . $socket->errMsg);
38+
}
39+
});
40+
}
41+
});
42+
43+
?>
44+
--EXPECT--
45+
DONE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
swoole_http_server_coro: bad request
3+
--SKIPIF--
4+
<?php require __DIR__ . '/../include/skipif.inc'; ?>
5+
--FILE--
6+
<?php
7+
require __DIR__ . '/../include/bootstrap.php';
8+
9+
use Swoole\Coroutine;
10+
use Swoole\Coroutine\Http\Server;
11+
use Swoole\Coroutine\Socket;
12+
use Swoole\Http\Request;
13+
use Swoole\Http\Response;
14+
15+
const REQUEST =
16+
"GET /websocket HTTP/1.1\r\n" .
17+
"Host: 127.0.0.1\r\n" .
18+
"Connection: Upgrade\r\n" .
19+
"Upgrade: websocket\r\n" .
20+
"Sec-WebSocket-Version: 13\r\n" .
21+
"Sec-WebSocket-Key: ZE5FYi8lZlZBbnlrTmxYKQ==\r\n\r\n" .
22+
"\x81\x0cHello Swoole";
23+
24+
Coroutine\run(function () {
25+
$server = new Server('127.0.0.1', 0);
26+
Coroutine::create(function () use ($server) {
27+
$server->handle('/', function (Request $request, Response $websocket) use ($server) {
28+
$websocket->upgrade();
29+
$frame = $websocket->recv();
30+
if ($frame) {
31+
$websocket->push($frame);
32+
}
33+
});
34+
$server->start();
35+
});
36+
Coroutine::sleep(0.001);
37+
Coroutine::create(function () use ($server) {
38+
$socket = new Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
39+
if (Assert::true($socket->connect('127.0.0.1', $server->port, -1))) {
40+
$ret = $socket->sendAll(REQUEST);
41+
Assert::same($ret, strlen(REQUEST));
42+
Assert::contains($socket->recv(), 'Hello Swoole');
43+
$server->shutdown();
44+
echo "DONE\n";
45+
}
46+
});
47+
});
48+
49+
?>
50+
--EXPECT--
51+
DONE

0 commit comments

Comments
 (0)