Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
danielkurecka committed Mar 6, 2020
0 parents commit 4097f24
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/vendor/*
/composer.lock
26 changes: 26 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "daku/nette-guzzle-bluescreen",
"license": "MIT",

"require": {
"php": ">=7.1.0",
"nette/di": "^2.4 | ^3.0",
"guzzlehttp/guzzle": "^6.0 | ^7.0"
},

"require-dev": {
"nette/nette": "^2.4 | ^3.0"
},

"autoload": {
"psr-4": {
"Daku\\Nette\\Guzzle\\": "src"
}
},

"autoload-dev": {
"psr-4": {
"Daku\\Nette\\Guzzle\\Tests\\TestApp\\": "tests/testApp/app"
}
}
}
180 changes: 180 additions & 0 deletions src/GuzzleBlueScreenExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<?php

declare(strict_types=1);

namespace Daku\Nette\Guzzle;

use GuzzleHttp\Exception\RequestException;
use Nette\DI\CompilerExtension;
use Nette\PhpGenerator\ClassType;
use Psr\Http\Message\MessageInterface;

class GuzzleBlueScreenExtension extends CompilerExtension
{

/** @var int The maximum body length that will be logged, if exceeded it will be truncted. */
public static $maxBodyLength = 100 * 1024;

public static $prettyPrint = true;


public function loadConfiguration()
{
$config = $this->validateConfig([
'maxBodyLength' => self::$maxBodyLength,
'prettyPrint' => self::$prettyPrint
]);

self::$prettyPrint = $config['prettyPrint'];
self::$maxBodyLength = $config['maxBodyLength'];
}


public function afterCompile(ClassType $class)
{
$initialize = $class->getMethod('initialize');
$initialize->addBody("Tracy\Debugger::getBlueScreen()->addPanel(['" . self::class . "', 'renderException']);");
}


public static function renderException(?\Throwable $e)
{
if ($e instanceof RequestException) {
$request = $e->getRequest();
$response = $e->getResponse();
$panel = '<p><b data-tracy-ref="^+" class="tracy-toggle">Request headers:</b></p>' . self::formatHeaders($request);
$panel .= '<p><b data-tracy-ref="^+" class="tracy-toggle">Reqest body:</b></p>' . self::formatBody($request);
$panel .= '<p><b data-tracy-ref="^+" class="tracy-toggle">Response headers:</b></p>' . self::formatHeaders($response);
$panel .= '<p><b data-tracy-ref="^+" class="tracy-toggle">Response body:</b></p>' . self::formatBody($response);
return ['tab' => 'Guzzle', 'panel' => $panel];
}
return null;
}


public static function formatHeaders(?MessageInterface $message)
{
$return = '<pre class="code">';
if ($message === null) {
$return .= '<i>unknown</i>';

} else {
foreach ($message->getHeaders() as $name => $values) {
foreach ($values as $value) {
$return .= "$name: $value\n";
}
}
}
$return .= '</pre>';
return $return;
}


public static function formatBody(?MessageInterface $message)
{
$truncated = false;
if ($message === null) {
$content = '<i>unknown</i>';

} else {
$body = $message->getBody();

if ($body->getSize() === 0) {
$content = '<i>empty</i>';

} else {
$body->rewind();

if ($body->getSize() > self::$maxBodyLength) {
$content = $body->read(self::$maxBodyLength);
$truncated = true;
} else {
$content = $body->getContents();
}

if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $content)) {
$content = '<i>unprintable content</i>';

} elseif (self::$prettyPrint && strpos($message->getHeaderLine('Content-Type'), 'application/json') !== false) {
$content = htmlspecialchars(self::prettyPrintJson($content));

} else {
$content = htmlspecialchars($content);
}
}
}

return '<pre class="code">' . $content . ($truncated ? "\n<i>(truncated...)</i>" : '') . '</pre>';
}


// source: https://stackoverflow.com/a/9776726
public static function prettyPrintJson(string $json)
{
$result = '';
$level = 0;
$inQuotes = false;
$inEscape = false;
$endsLineLevel = null;
$length = strlen($json);

for ($i = 0; $i < $length; $i++) {
$char = $json[$i];
$newLineLevel = null;
$post = '';
if ($endsLineLevel !== null) {
$newLineLevel = $endsLineLevel;
$endsLineLevel = null;
}
if ($inEscape) {
$inEscape = false;
} else {
if ($char === '"') {
$inQuotes = !$inQuotes;
} else {
if (!$inQuotes) {
switch ($char) {
case '}':
case ']':
$level--;
$endsLineLevel = null;
$newLineLevel = $level;
break;

case '{':
case '[':
$level++;
case ',':
$endsLineLevel = $level;
break;

case ':':
$post = ' ';
break;

case ' ':
case "\t":
case "\n":
case "\r":
$char = '';
$endsLineLevel = $newLineLevel;
$newLineLevel = null;
break;
}
} else {
if ($char === '\\') {
$inEscape = true;
}
}
}
}
if ($newLineLevel !== null) {
$result .= "\n" . str_repeat(" ", $newLineLevel);
}
$result .= $char . $post;
}

return $result;
}

}
2 changes: 2 additions & 0 deletions tests/testApp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/temp/*
!/temp/.htaccess
1 change: 1 addition & 0 deletions tests/testApp/app/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Require all denied
23 changes: 23 additions & 0 deletions tests/testApp/app/HomepagePresenter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Daku\Nette\Guzzle\Tests\TestApp;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Psr7\Request;
use Nette\Application\UI\Presenter;

class HomepagePresenter extends Presenter
{

public function renderDefault()
{
$client = new Client;
$request = new Request('GET', 'http://httpbin.org/json');
$response = $client->send($request);
throw BadResponseException::create($request, $response);
}

}
13 changes: 13 additions & 0 deletions tests/testApp/app/config.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
application:
mapping:
*: Daku\Nette\Guzzle\Tests\TestApp\*Presenter

services:
router: Nette\Application\Routers\SimpleRouter('Homepage:default')

extensions:
guzzleBluescreen: Daku\Nette\Guzzle\GuzzleBlueScreenExtension

guzzleBluescreen:
# maxBodyLength: 20
# prettyPrint: true
10 changes: 10 additions & 0 deletions tests/testApp/app/templates/Homepage.default.latte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test app</title>
</head>
<body>

</body>
</html>
13 changes: 13 additions & 0 deletions tests/testApp/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

require __DIR__ . '/../../vendor/autoload.php';

$configurator = new Nette\Configurator;
$configurator->setDebugMode(true);
$configurator->enableDebugger();
$configurator->setTempDirectory(__DIR__ . '/temp');
$configurator->addConfig(__DIR__ . '/app/config.neon');
$container = $configurator->createContainer();
$container->getByType(Nette\Application\Application::class)->run();
1 change: 1 addition & 0 deletions tests/testApp/temp/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Require all denied

0 comments on commit 4097f24

Please sign in to comment.