Accept text/plain events from the Plausible tracker
dependabot-auto-merge / dependabot (pull_request_target) Skipped
Fix PHP code style issues / php-code-styling (push) Successful in 6s
PHPStan / phpstan (push) Successful in 2m38s
run-tests / P8.3 - L11.* - prefer-lowest - ubuntu-latest (push) Failing after 33s
run-tests / P8.4 - L11.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L11.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L12.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L12.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L12.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L12.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L13.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L13.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L13.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L13.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L11.* - prefer-stable - ubuntu-latest (push) Canceled after 1s
dependabot-auto-merge / dependabot (pull_request_target) Skipped
Fix PHP code style issues / php-code-styling (push) Successful in 6s
PHPStan / phpstan (push) Successful in 2m38s
run-tests / P8.3 - L11.* - prefer-lowest - ubuntu-latest (push) Failing after 33s
run-tests / P8.4 - L11.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L11.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L12.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L12.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L12.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L12.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L13.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L13.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L13.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L13.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L11.* - prefer-stable - ubuntu-latest (push) Canceled after 1s
The Plausible tracker posts its JSON payload with Content-Type text/plain, which Laravel does not parse, so every real event failed validation and was redirected instead of being forwarded. - Decode the raw body when the request is not JSON - Respond with 400 instead of a redirect on invalid non-JSON requests - Trim trailing slash from the configured domain when forwarding events - Add a 5s timeout and respond with 502 when Plausible is unreachable
This commit is contained in:
3 files changed
+98
-4
No files matched your search
@@ -2,18 +2,30 @@
|
||||
|
||||
namespace Mattitja\LaravelPlausibleProxy\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Mattitja\LaravelPlausibleProxy\Http\Requests\PlausibleEventRequest;
|
||||
|
||||
class PlausibleEventApiController
|
||||
{
|
||||
public function __invoke(PlausibleEventRequest $request): Response
|
||||
{
|
||||
$upstream = Http::withHeaders([
|
||||
'User-Agent' => (string) $request->userAgent(),
|
||||
'X-Forwarded-For' => (string) $request->ip(),
|
||||
])->post(config('plausible-proxy.domain').'/api/event', $request->all());
|
||||
$url = rtrim((string) config('plausible-proxy.domain'), '/').'/api/event';
|
||||
|
||||
try {
|
||||
$upstream = Http::timeout(5)
|
||||
->withHeaders([
|
||||
'User-Agent' => (string) $request->userAgent(),
|
||||
'X-Forwarded-For' => (string) $request->ip(),
|
||||
])
|
||||
->post($url, $request->all());
|
||||
} catch (ConnectionException $e) {
|
||||
Log::error('Failed to forward Plausible event: '.$e->getMessage());
|
||||
|
||||
return response('Bad Gateway', 502);
|
||||
}
|
||||
|
||||
return response($upstream->body(), $upstream->status())
|
||||
->header('Content-Type', $upstream->header('Content-Type') ?: 'text/plain');
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Mattitja\LaravelPlausibleProxy\Http\Requests;
|
||||
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
||||
|
||||
class PlausibleEventRequest extends FormRequest
|
||||
{
|
||||
@@ -11,6 +13,32 @@ class PlausibleEventRequest extends FormRequest
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Plausible tracker sends its JSON payload with a text/plain content
|
||||
* type, which Laravel does not parse automatically.
|
||||
*/
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
if ($this->isJson()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payload = json_decode($this->getContent(), true);
|
||||
|
||||
if (is_array($payload)) {
|
||||
$this->merge($payload);
|
||||
}
|
||||
}
|
||||
|
||||
protected function failedValidation(Validator $validator): void
|
||||
{
|
||||
if (! $this->expectsJson()) {
|
||||
throw new HttpResponseException(response('Bad Request', 400));
|
||||
}
|
||||
|
||||
parent::failedValidation($validator);
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
|
||||
Reference in new issue
Block a user