diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 68636ec..b8e21c3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,7 +11,7 @@ jobs: - 8080:80 strategy: matrix: - php-versions: [ '8.0', '8.1', '8.2', '8.3', '8.4' ] + php-versions: [ '8.1', '8.2', '8.3', '8.4' ] composer-options: [ '--prefer-lowest', ''] runs-on: ubuntu-latest steps: diff --git a/Controller/ReplayController.php b/Controller/ReplayController.php index d3acafd..5f8da4e 100644 --- a/Controller/ReplayController.php +++ b/Controller/ReplayController.php @@ -3,9 +3,15 @@ namespace evaisse\SimpleHttpBundle\Controller; use evaisse\SimpleHttpBundle\Service\Helper; +use evaisse\SimpleHttpBundle\Service\ReplayRequestResolver; +use evaisse\SimpleHttpBundle\Service\ReplayRequestSignature; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Annotation\Route; /** @@ -14,19 +20,43 @@ */ class ReplayController extends AbstractController { - public function __construct(protected Helper $serviceHelper) - { + public function __construct( + protected Helper $serviceHelper, + private ReplayRequestResolver $replayRequestResolver, + private ReplayRequestSignature $replayRequestSignature, + private bool $debug + ) { } - #[Route('/http-replay', name: 'simple_http.replay_request')] + #[Route('/http-replay', name: 'simple_http.replay_request', methods: ['POST'])] public function replayRequestAction(Request $request): Response { - $request = json_decode($request->request->get('request')); + if (!$this->debug || !$this->replayRequestResolver->isAvailable()) { + throw new NotFoundHttpException('Replay is only available with the profiler enabled.'); + } - $service = $this->serviceHelper->prepare($request->method, $request->uri); - $service->getRequest()->setContent($request->content); + $token = $request->request->getString('token'); + $signature = $request->request->getString('_token'); + $callIndex = filter_var( + $request->request->get('callIndex'), + FILTER_VALIDATE_INT, + ['options' => ['min_range' => 0]] + ); - foreach ($request->headers as $header) { + if ('' === $token || false === $callIndex) { + throw new BadRequestHttpException('Invalid replay request.'); + } + + if (!$this->replayRequestSignature->isValid($token, $callIndex, $signature)) { + throw new AccessDeniedHttpException('Invalid replay token.'); + } + + $storedRequest = $this->replayRequestResolver->resolve($token, $callIndex); + + $service = $this->serviceHelper->prepare($storedRequest['method'], $storedRequest['uri']); + $service->getRequest()->setContent($storedRequest['content']); + + foreach ($storedRequest['headers'] as $header) { if (fnmatch('*:*', $header)) { list($headerName, $headerValue) = explode(':', $header, 2); $headerName = trim($headerName); @@ -35,15 +65,14 @@ public function replayRequestAction(Request $request): Response } } - foreach ($request->cookies as $cookieName => $cookieValue) { + foreach ($storedRequest['cookies'] as $cookieName => $cookieValue) { $service->getRequest()->cookies->set($cookieName, $cookieValue); } - $this->serviceHelper->execute([ $service, ]); - return new Response('ok'); + return new JsonResponse(['status' => 'ok']); } } diff --git a/README.md b/README.md index 65e9ea1..d780eac 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,13 @@ SimpleHttpBundle ### While Still maintained, I recommand you to replace this bundle with the [symfony/http-client](https://github.com/symfony/http-client) with has better support and a handy plug-in support. -A symfony2/3/4/5 http client bundle built on the httpfoundation component (instead of guzzle), using cURL as engine. +A Symfony 5.4/6.x HTTP client bundle built on the HttpFoundation component (instead of guzzle), using cURL as engine. + +Requirements +====== + +- PHP 8.1+ +- Symfony 5.4 or 6.x [](https://coveralls.io/r/evaisse/SimpleHttpBundle?branch=master) @@ -78,6 +84,8 @@ or You can now resend an http call directly from the profiler debug panel + +Replay requests are now resolved server-side from the profiler storage. The browser only sends the profiler token and request index, not the serialized request payload. Panels details @@ -200,4 +208,3 @@ $http->execute([ ``` - diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 956ab88..d1c14f3 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -5,7 +5,13 @@ services: autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. public: false - evaisse\SimpleHttpBundle\Controller\ReplayController: ~ + evaisse\SimpleHttpBundle\Controller\ReplayController: + arguments: + $debug: '%kernel.debug%' + evaisse\SimpleHttpBundle\Service\ReplayRequestResolver: ~ + evaisse\SimpleHttpBundle\Service\ReplayRequestSignature: + arguments: + $secret: '%kernel.secret%' evaisse\SimpleHttpBundle\Http\Kernel: ~ evaisse\SimpleHttpBundle\Service\Helper: ~ @@ -38,6 +44,7 @@ services: - { name: data_collector, template: "@SimpleHttp/Collector/profiler", id: "simplehttpprofiler" } evaisse\SimpleHttpBundle\Twig\Extension: - arguments: ["@twig.loader"] + arguments: + $loader: "@twig.loader" tags: - - { name: twig.extension } \ No newline at end of file + - { name: twig.extension } diff --git a/Resources/public/simple-http-bundle.css b/Resources/public/simple-http-bundle.css index 06e2e26..6f99102 100644 --- a/Resources/public/simple-http-bundle.css +++ b/Resources/public/simple-http-bundle.css @@ -196,7 +196,7 @@ a.http-call__index:hover { display: inline; } -button[data-simple-http-replay] { +button[data-simple-http-replay-token] { border: 1px solid #CCD; background: #EEF; color: #777; @@ -216,13 +216,13 @@ button[data-simple-http-replay] { } -button[data-simple-http-replay] img { +button[data-simple-http-replay-token] img { float: left; zoom: 75%; margin-right: 10px; } -button[data-simple-http-replay] img.rotating { +button[data-simple-http-replay-token] img.rotating { -webkit-animation: rotating 2s linear infinite; } @@ -266,4 +266,4 @@ button[data-simple-http-replay] img.rotating { overflow-x: hidden; text-decoration: none; border-bottom: 0; -} \ No newline at end of file +} diff --git a/Resources/public/simple-http-bundle.js b/Resources/public/simple-http-bundle.js index 76d2153..e74f840 100644 --- a/Resources/public/simple-http-bundle.js +++ b/Resources/public/simple-http-bundle.js @@ -2,13 +2,13 @@ * */ (function ($) { - function replayRequest(url, request, callback) { - window.console && console.log('Replay request :', request); - + function replayRequest(url, token, callIndex, signature, callback) { $.post({ url: url, data: { - request: JSON.stringify(request) + token: token, + callIndex: callIndex, + _token: signature } }).done(function (data, success, xhr) { // Wait 1 second to be sure the profiler has been generated and can be accessed @@ -69,7 +69,7 @@ filterByHost(event.target.value); }); - $(element).find('[data-simple-http-replay]').click(function (replay, i) { + $(element).find('[data-simple-http-replay-token]').click(function (replay, i) { var $panel = $(this).closest('.http-call'), $butt = $(this); @@ -78,7 +78,12 @@ $butt.prop('disabled', true); - replayRequest($(this).data('simpleHttpReplayUrl'), $(this).data('simpleHttpReplay'), function (error, block) { + replayRequest( + $(this).data('simpleHttpReplayUrl'), + $(this).data('simpleHttpReplayToken'), + $(this).data('simpleHttpReplayIndex'), + $(this).data('simpleHttpReplaySignature'), + function (error, block) { if (error) { alert('Error on replay request'); } @@ -90,7 +95,8 @@ .appendTo($panel.find('.http-call__replay-calls:first')); $(document).trigger('setup', [block]); // init events $buttImg.removeClass('rotating'); - }); + } + ); }); @@ -105,4 +111,3 @@ })(jQuery); - diff --git a/Resources/views/Collector/partials/call.html.twig b/Resources/views/Collector/partials/call.html.twig index 444504b..492888c 100644 --- a/Resources/views/Collector/partials/call.html.twig +++ b/Resources/views/Collector/partials/call.html.twig @@ -137,7 +137,9 @@