Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for formatting large request bodies #22

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/vendor/
composer.lock
.phpunit.result.cache
8 changes: 5 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
"description": "Get the cURL shell command from a Guzzle request",
"require": {
"php": ">=5.5.0",
"guzzlehttp/guzzle": "^6.0",
"psr/log": "^1.0"
"guzzlehttp/guzzle": "^6.1|^7.0",
"guzzlehttp/psr7":"^1.7|^2.0",
"psr/log": "^1.0|^2.0|^3.0",
"symfony/process": "^3.3|^4.0|^5.0|^6.0"
},
"require-dev": {
"phpunit/phpunit": "^4.2.2"
"phpunit/phpunit": "^6|^7|^8|^9"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<phpunit bootstrap="vendor/autoload.php"
colors="true">
<testsuites>
<testsuite>
<testsuite name="tests">
<directory>tests</directory>
</testsuite>
</testsuites>
Expand Down
18 changes: 13 additions & 5 deletions src/Formatter/CurlFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use GuzzleHttp\Cookie\CookieJarInterface;
use GuzzleHttp\Cookie\SetCookie;
use Psr\Http\Message\RequestInterface;
use Symfony\Component\Process\Process;

/**
* Class CurlFormatter it formats a Guzzle request to a cURL shell command
Expand Down Expand Up @@ -134,7 +135,7 @@ protected function extractBodyArgument(RequestInterface $request)
if ($contents) {
// clean input of null bytes
$contents = str_replace(chr(0), '', $contents);
$this->addOption('d', escapeshellarg($contents));
$this->addOption('d', $this->escapeShellArgument($contents));
}

//if get request has data Add G otherwise curl will make a post request
Expand Down Expand Up @@ -168,7 +169,7 @@ protected function extractCookiesArgument(RequestInterface $request, array $opti
}

if ($values) {
$this->addOption('b', escapeshellarg(implode('; ', $values)));
$this->addOption('b', $this->escapeShellArgument(implode('; ', $values)));
}
}

Expand All @@ -183,12 +184,12 @@ protected function extractHeadersArgument(RequestInterface $request)
}

if ('user-agent' === strtolower($name)) {
$this->addOption('A', escapeshellarg($header[0]));
$this->addOption('A', $this->escapeShellArgument($header[0]));
continue;
}

foreach ((array)$header as $headerValue) {
$this->addOption('H', escapeshellarg("{$name}: {$headerValue}"));
$this->addOption('H', $this->escapeShellArgument("{$name}: {$headerValue}"));
}
}
}
Expand Down Expand Up @@ -228,6 +229,13 @@ protected function extractArguments(RequestInterface $request, array $options)
*/
protected function extractUrlArgument(RequestInterface $request)
{
$this->addCommandPart(escapeshellarg((string)$request->getUri()->withFragment('')));
$this->addCommandPart($this->escapeShellArgument((string)$request->getUri()->withFragment('')));
}

protected function escapeShellArgument($argument)
{
$process = new Process([$argument]);
$escaped = $process->getCommandLine();
return $escaped;
}
}
29 changes: 15 additions & 14 deletions tests/Client/RequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@

use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Utils;
use Namshi\Cuzzle\Formatter\CurlFormatter;
use PHPUnit\Framework\TestCase;

class RequestTest extends \PHPUnit_Framework_TestCase
class RequestTest extends TestCase
{
/**
* @var CurlFormatter
*/
protected $curlFormatter;

public function setUp()
public function setUp(): void
{
$this->client = new Client();
$this->curlFormatter = new CurlFormatter();
Expand All @@ -27,49 +28,49 @@ public function testGetWithCookies()
$jar = CookieJar::fromArray(['Foo' => 'Bar', 'identity' => 'xyz'], 'local.example');
$curl = $this->curlFormatter->format($request, ['cookies' => $jar]);

$this->assertNotContains("-H 'Host: local.example'", $curl);
$this->assertContains("-b 'Foo=Bar; identity=xyz'", $curl);
$this->assertStringNotContainsString("-H 'Host: local.example'", $curl);
$this->assertStringContainsString("-b 'Foo=Bar; identity=xyz'", $curl);
}

public function testPOST()
{
$request = new Request('POST', 'http://local.example', [], Psr7\stream_for('foo=bar&hello=world'));
$request = new Request('POST', 'http://local.example', [], Utils::streamFor('foo=bar&hello=world'));
$curl = $this->curlFormatter->format($request);

$this->assertContains("-d 'foo=bar&hello=world'", $curl);
$this->assertStringContainsString("-d 'foo=bar&hello=world'", $curl);
}

public function testPUT()
{
$request = new Request('PUT', 'http://local.example', [], Psr7\stream_for('foo=bar&hello=world'));
$request = new Request('PUT', 'http://local.example', [], Utils::streamFor('foo=bar&hello=world'));
$curl = $this->curlFormatter->format($request);

$this->assertContains("-d 'foo=bar&hello=world'", $curl);
$this->assertContains('-X PUT', $curl);
$this->assertStringContainsString("-d 'foo=bar&hello=world'", $curl);
$this->assertStringContainsString('-X PUT', $curl);
}

public function testDELETE()
{
$request = new Request('DELETE', 'http://local.example');
$curl = $this->curlFormatter->format($request);

$this->assertContains('-X DELETE', $curl);
$this->assertStringContainsString('-X DELETE', $curl);
}

public function testHEAD()
{
$request = new Request('HEAD', 'http://local.example');
$curl = $this->curlFormatter->format($request);

$this->assertContains("curl 'http://local.example' --head", $curl);
$this->assertStringContainsString("curl 'http://local.example' --head", $curl);
}

public function testOPTIONS()
{
$request = new Request('OPTIONS', 'http://local.example');
$curl = $this->curlFormatter->format($request);

$this->assertContains('-X OPTIONS', $curl);
$this->assertStringContainsString('-X OPTIONS', $curl);
}

}
}
46 changes: 29 additions & 17 deletions tests/Formatter/CurlFormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

use Namshi\Cuzzle\Formatter\CurlFormatter;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Utils;
use PHPUnit\Framework\TestCase;

class CurlFormatterTest extends \PHPUnit_Framework_TestCase
class CurlFormatterTest extends TestCase
{
/**
* @var CurlFormatter
*/
protected $curlFormatter;

public function setUp()
public function setUp(): void
{
$this->curlFormatter = new CurlFormatter();
}
Expand Down Expand Up @@ -69,7 +71,7 @@ public function testGETWithQueryString()

$this->assertEquals("curl 'http://example.local?foo=bar'", $curl);

$body = \GuzzleHttp\Psr7\stream_for(http_build_query(['foo' => 'bar', 'hello' => 'world'], '', '&'));
$body = Utils::streamFor(http_build_query(['foo' => 'bar', 'hello' => 'world'], '', '&'));

$request = new Request('GET', 'http://example.local',[],$body);
$curl = $this->curlFormatter->format($request);
Expand All @@ -80,57 +82,57 @@ public function testGETWithQueryString()

public function testPOST()
{
$body = \GuzzleHttp\Psr7\stream_for(http_build_query(['foo' => 'bar', 'hello' => 'world'], '', '&'));
$body = Utils::streamFor(http_build_query(['foo' => 'bar', 'hello' => 'world'], '', '&'));

$request = new Request('POST', 'http://example.local', [], $body);
$curl = $this->curlFormatter->format($request);

$this->assertContains("-d 'foo=bar&hello=world'", $curl);
$this->assertNotContains(" -G ", $curl);
$this->assertStringContainsString("-d 'foo=bar&hello=world'", $curl);
$this->assertStringNotContainsString(" -G ", $curl);
}

public function testHEAD()
{
$request = new Request('HEAD', 'http://example.local');
$curl = $this->curlFormatter->format($request);

$this->assertContains("--head", $curl);
$this->assertStringContainsString("--head", $curl);
}

public function testOPTIONS()
{
$request = new Request('OPTIONS', 'http://example.local');
$curl = $this->curlFormatter->format($request);

$this->assertContains("-X OPTIONS", $curl);
$this->assertStringContainsString("-X OPTIONS", $curl);
}

public function testDELETE()
{
$request = new Request('DELETE', 'http://example.local/users/4');
$curl = $this->curlFormatter->format($request);

$this->assertContains("-X DELETE", $curl);
$this->assertStringContainsString("-X DELETE", $curl);
}

public function testPUT()
{
$request = new Request('PUT', 'http://example.local', [], \GuzzleHttp\Psr7\stream_for('foo=bar&hello=world'));
$request = new Request('PUT', 'http://example.local', [], Utils::streamFor('foo=bar&hello=world'));
$curl = $this->curlFormatter->format($request);

$this->assertContains("-d 'foo=bar&hello=world'", $curl);
$this->assertContains("-X PUT", $curl);
$this->assertStringContainsString("-d 'foo=bar&hello=world'", $curl);
$this->assertStringContainsString("-X PUT", $curl);
}

public function testProperBodyReading()
{
$request = new Request('PUT', 'http://example.local', [], \GuzzleHttp\Psr7\stream_for('foo=bar&hello=world'));
$request = new Request('PUT', 'http://example.local', [], Utils::streamFor('foo=bar&hello=world'));
$request->getBody()->getContents();

$curl = $this->curlFormatter->format($request);

$this->assertContains("-d 'foo=bar&hello=world'", $curl);
$this->assertContains("-X PUT", $curl);
$this->assertStringContainsString("-d 'foo=bar&hello=world'", $curl);
$this->assertStringContainsString("-X PUT", $curl);
}

/**
Expand All @@ -140,11 +142,11 @@ public function testExtractBodyArgument($headers, $body)
{
// clean input of null bytes
$body = str_replace(chr(0), '', $body);
$request = new Request('POST', 'http://example.local', $headers, \GuzzleHttp\Psr7\stream_for($body));
$request = new Request('POST', 'http://example.local', $headers, Utils::streamFor($body));

$curl = $this->curlFormatter->format($request);

$this->assertContains('foo=bar&hello=world', $curl);
$this->assertStringContainsString('foo=bar&hello=world', $curl);
}

/**
Expand All @@ -161,4 +163,14 @@ public function getHeadersAndBodyData()
],
];
}

public function testLongArgument()
{
ini_set('memory_limit', -1);
$body = str_repeat('A', 1024*1024*64);
$request = new Request('POST', 'http://example.local', [], Utils::streamFor($body));

$curl = $this->curlFormatter->format($request);
$this->assertStringContainsString($body, $curl);
}
}
5 changes: 3 additions & 2 deletions tests/Middleware/CurlFormatterMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Handler\MockHandler;
use Namshi\Cuzzle\Middleware\CurlFormatterMiddleware;
use PHPUnit\Framework\TestCase;

class CurlFormatterMiddlewareTest extends \PHPUnit_Framework_TestCase
class CurlFormatterMiddlewareTest extends TestCase
{
public function testGet()
{
$mock = new MockHandler([new Response(204)]);
$handler = HandlerStack::create($mock);
$logger = $this->getMock(\Psr\Log\LoggerInterface::class);
$logger = $this->getMockForAbstractClass(\Psr\Log\LoggerInterface::class);

$logger
->expects($this->once())
Expand Down