Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Protocols/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public static function input(string $buffer, TcpConnection $connection): int
// Disallow duplicate Content-Length headers (adjacent or separated)
. '(?![\s\S]*\r\nContent-Length[ \t]*:[^\r\n]*\r\n(?:[\s\S]*?\r\n)?Content-Length[ \t]*:)'
// Match request line: METHOD SP request-target SP HTTP-version CRLF
. '(?:(?-i:GET|POST|OPTIONS|HEAD|DELETE|PUT|PATCH) )+(?:/[^\x00-\x20\x7f]*)+(?: (?-i:HTTP)/1.[0-9])\r\n'
. '(?:(?-i:GET|POST|OPTIONS|HEAD|DELETE|PUT|PATCH) )+(?:(http|https):/)*(?:/[^\x00-\x20\x7f]*)+(?: (?-i:HTTP)/1.[0-9])\r\n'
// Flag case-insensitive
. '~i';

Expand Down
83 changes: 80 additions & 3 deletions tests/Unit/Protocols/HttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,26 @@
"GET / HTTP/1.2\r\n\r\n",
18, // strlen("GET / HTTP/1.2\r\n\r\n")
],
'allow full url in request-target (compatibility)' => [
"GET http://example.com/ HTTP/1.1\r\n\r\n",
strlen("GET http://example.com/ HTTP/1.1\r\n\r\n"),
],
'allow full url with port in request-target (compatibility)' => [
"GET http://example.com:8080/ HTTP/1.1\r\n\r\n",
strlen("GET http://example.com:8080/ HTTP/1.1\r\n\r\n"),
],
'allow full url with query in request-target (compatibility)' => [
"GET http://example.com/search?q=workerman HTTP/1.1\r\n\r\n",
strlen("GET http://example.com/search?q=workerman HTTP/1.1\r\n\r\n"),
],
'allow full url with uppercase scheme in request-target (compatibility)' => [
"GET HTTP://example.com/ HTTP/1.1\r\n\r\n",
strlen("GET HTTP://example.com/ HTTP/1.1\r\n\r\n"),
],
'allow full url with path in request-target (compatibility)' => [
"GET https://example.com/foo/bar HTTP/1.1\r\n\r\n",
strlen("GET https://example.com/foo/bar HTTP/1.1\r\n\r\n"),
],
]);

it('rejects invalid request-line cases in ::input', function (string $buffer) {
Expand All @@ -151,9 +171,6 @@
'leading whitespace before method is not allowed' => [
" GET / HTTP/1.1\r\n\r\n",
],
'absolute-form request-target is not supported' => [
"GET http://example.com/ HTTP/1.1\r\n\r\n",
],
'asterisk-form request-target is not supported (including OPTIONS *)' => [
"OPTIONS * HTTP/1.1\r\n\r\n",
],
Expand Down Expand Up @@ -187,6 +204,66 @@
'space after version is not allowed' => [
"GET / http/1.1 \r\n\r\n",
],
'missing space between method and path' => [
"GET/ HTTP/1.1\r\n\r\n",
],
'missing space between path and version' => [
"GET /HTTP/1.1\r\n\r\n",
],
'missing version' => [
"GET / \r\n\r\n",
],
'missing path' => [
"GET HTTP/1.1\r\n\r\n",
],
'missing method' => [
" / HTTP/1.1\r\n\r\n",
],
'empty request-line' => [
"\r\n\r\n",
],
'bad scheme' => [
"GET ftp://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n",
],
'bad authority in absolute-form request-target' => [
"GET http://exa mple.com/ HTTP/1.1\r\n\r\n",
],
'bad path in absolute-form request-target' => [
"GET http://example.com/fo o HTTP/1.1\r\n\r\n",
],
'bad query in absolute-form request-target' => [
"GET http://example.com/search?q=wor k HTTP/1.1\r\n\r\n",
],
'bad fragment in absolute-form request-target' => [
"GET http://example.com/#frag ment HTTP/1.1\r\n\r\n",
],
'bad port in absolute-form request-target' => [
"GET http://example.com:80 80/ HTTP/1.1\r\n\r\n",
],
// 'bad port number in absolute-form request-target' => [
// "GET http://example.com:abc/ HTTP/1.1\r\n\r\n",
// ],
// 'bad port number in absolute-form request-target (too large)' => [
// "GET http://example.com:99999/ HTTP/1.1\r\n\r\n",
// ],
// 'bad port number in absolute-form request-target (negative)' => [
// "GET http://example.com:-80/ HTTP/1.1\r\n\r\n",
// ],
// 'bad port number in absolute-form request-target (non-digit characters)' => [
// "GET http://example.com:8o80/ HTTP/1.1\r\n\r\n",
// ],
// 'bad port number in absolute-form request-target (empty)' => [
// "GET http://example.com:/ HTTP/1.1\r\n\r\n",
// ],
// 'bad port number in absolute-form request-target (leading zero)' => [
// "GET http://example.com:080/ HTTP/1.1\r\n\r\n",
// ],
'bad full url in request-target (invalid characters in host)' => [
"GET http://exa mple.com/ HTTP/1.1\r\n\r\n",
],
'bad full url in request-target' => [
"GET htp://example.com/foo HTTP/1.1\r\n\r\n",
],

]);

Expand Down
Loading