diff --git a/README.md b/README.md index 1ab56e1..5b5e463 100644 --- a/README.md +++ b/README.md @@ -282,6 +282,19 @@ WebhookCall::create() ->dispatch(); ``` +### Using a proxy + +You can direct webhooks through a proxy by specifying the `proxy` key in the `webhook-server` config file. To set a proxy for a specific +request, you can use the `useProxy` call. + +```php +WebhookCall::create() + ->useProxy('http://proxy.server:3128') + ... +``` + +The proxy specification follows the [guzzlehttp proxy format](https://docs.guzzlephp.org/en/stable/request-options.html#proxy) + ### Verifying the SSL certificate of the receiving app When using an URL that starts with `https://` the package will verify if the SSL certificate of the receiving party is valid. If it is not, we will consider the webhook call failed. We don't recommend this, but you can turn off this verification by setting the `verify_ssl` key in the `webhook-server` config file to `false`. diff --git a/config/webhook-server.php b/config/webhook-server.php index 834ac95..c973b79 100644 --- a/config/webhook-server.php +++ b/config/webhook-server.php @@ -17,6 +17,13 @@ */ 'http_verb' => 'post', + /* + * Proxies to use for request. + * + * See https://docs.guzzlephp.org/en/stable/request-options.html#proxy + */ + 'proxy' => null, + /* * This class is responsible for calculating the signature that will be added to * the headers of the webhook request. A webhook client can use the signature diff --git a/src/CallWebhookJob.php b/src/CallWebhookJob.php index 2550d9a..5c67a29 100644 --- a/src/CallWebhookJob.php +++ b/src/CallWebhookJob.php @@ -27,6 +27,8 @@ class CallWebhookJob implements ShouldQueue public string $httpVerb; + public string|array|null $proxy = null; + public int $tries; public int $requestTimeout; @@ -78,7 +80,7 @@ public function handle() 'on_stats' => function (TransferStats $stats) { $this->transferStats = $stats; }, - ], $body)); + ], $body, is_null($this->proxy) ? [] : ['proxy' => $this->proxy])); if (! Str::startsWith($this->response->getStatusCode(), 2)) { throw new Exception('Webhook call failed'); diff --git a/src/WebhookCall.php b/src/WebhookCall.php index f7570ce..16af95b 100644 --- a/src/WebhookCall.php +++ b/src/WebhookCall.php @@ -44,7 +44,8 @@ public static function create(): self ->withHeaders($config['headers']) ->withTags($config['tags']) ->verifySsl($config['verify_ssl']) - ->throwExceptionOnFailure($config['throw_exception_on_failure']); + ->throwExceptionOnFailure($config['throw_exception_on_failure']) + ->useProxy($config['proxy']); } public function __construct() @@ -180,6 +181,13 @@ public function throwExceptionOnFailure(bool $throwExceptionOnFailure = true): s return $this; } + public function useProxy(array|string|null $proxy = null): self + { + $this->callWebhookJob->proxy = $proxy; + + return $this; + } + public function meta(array $meta): self { $this->callWebhookJob->meta = $meta; diff --git a/tests/CallWebhookJobTest.php b/tests/CallWebhookJobTest.php index 7fbf826..7d37731 100644 --- a/tests/CallWebhookJobTest.php +++ b/tests/CallWebhookJobTest.php @@ -158,6 +158,50 @@ public function it_can_disable_verifying_ssl() ->assertRequestsMade([$baseRequest]); } + /** @test */ + public function it_will_use_a_proxy() + { + $this + ->baseWebhook() + ->useProxy('https://proxy.test') + ->dispatch(); + + $baseRequest = $this->baseRequest(); + + $baseRequest['options']['proxy'] = 'https://proxy.test'; + + $this->artisan('queue:work --once'); + + $this + ->testClient + ->assertRequestsMade([$baseRequest]); + } + + /** @test */ + public function it_will_use_a_proxy_array() + { + $this + ->baseWebhook() + ->useProxy([ + 'http' => 'http://proxy.test', + 'https' => 'https://proxy.test' + ]) + ->dispatch(); + + $baseRequest = $this->baseRequest(); + + $baseRequest['options']['proxy'] = [ + 'http' => 'http://proxy.test', + 'https' => 'https://proxy.test' + ]; + + $this->artisan('queue:work --once'); + + $this + ->testClient + ->assertRequestsMade([$baseRequest]); + } + /** @test */ public function by_default_it_will_retry_3_times_with_the_exponential_backoff_strategy() {