laravel / reverb

Laravel Reverb provides a real-time WebSocket communication backend for Laravel applications.
https://reverb.laravel.com
MIT License
1.05k stars 76 forks source link

broadcast() event triggers weird OpennSSL error. #106

Closed rasmus0201 closed 5 months ago

rasmus0201 commented 5 months ago

Reverb Version

v1.0.0-beta4

Laravel Version

11.0.7

PHP Version

8.3.4

Description

In an existing application, trying to switch from Pusher to Reverb I get the following error when calling the broadcast(new MyEvent()) function:

OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0 (curl_errno is 56)

This event is triggered when a user calls an API endpoint, that should broadcast an event to other clients via a PresenceChannel.

I'm not really sure why i get the error as I can do the request via cURL CLI, but not PHP cURL:

curl -H 'Content-Type: application/json' \
     -d '{ "auth_key":"zhmgy7ydlqqdpuejplvw","auth_timestamp":1710932537, "auth_version": 1.0, "body_md5": "91dcf3a486bd51567cd491c799969ff9", "auth_signature": "41eb3db4b84b44aa7a7879822ec0f8dde4b1d856ed5eb53be042699de253860f"}' \
     -X POST \
     https://localhost:8080/apps/238231/events 

gives me a response:

{"name":["The name field is required."],"data":["The data field is required."],"channels":["The channels field is required when channel is not present."],"channel":["The channel field is required when channels is not present."]}

(I haven't investigated further if name/data/channels/channel is sent when using the broadcast() function, but that might be a second issue?)

I've also tried different settings for the broadcasting client_options but nothing works...

Steps To Reproduce

  1. New laravel app: composer create-project laravel/laravel:^11.0 example-app

  2. Install reverb: php artisan install:broadcasting

  3. Setup .env with https enabled for reverb. Since I'm working on a SPA-frontend in different repo, using vite dev, I've secured using mkcert, I've added the following to config/reverb.php. These are env variables are set to the path to certificates that mkcert creates:

    'options' => [
    'tls' => [
        'local_cert' => env('REVERB_LOCAL_CERT'),
        'local_pk' => env('REVERB_LOCAL_PK'),
    ],
    ],
  4. Run php artisan reverb:start --host="0.0.0.0" --port=8080 --hostname="localhost"

Then using any API endpoint (secured with sanctum) that dispatches a broadcast() call triggers the error. I've also made a test script which shows the error that can be run, around my Laravel backend API:

<?php
$ch = curl_init();

curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, "https://localhost:8080/apps/238231/events");
curl_setopt($ch, CURLOPT_POSTFIELDS, "{ \"auth_key\":\"zhmgy7ydlqqdpuejplvw\",\"auth_timestamp\":1710932537, \"auth_version\": 1.0, \"body_md5\": \"91dcf3a486bd51567cd491c799969ff9\", \"auth_signature\": \"41eb3db4b84b44aa7a7879822ec0f8dde4b1d856ed5eb53be042699de253860f\"}");

curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json'
]);

curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, fopen('php://stderr', 'w'));
curl_setopt($ch, CURLOPT_CERTINFO, true);

// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
// curl_setopt($ch, CURLOPT_SSLCERT, '/Users/rso/.ssl/localhost.pem');
// curl_setopt($ch, CURLOPT_SSLKEY, '/Users/rso/.ssl/localhost-key.pem');

$response = curl_exec($ch);

print_r([
    curl_errno($ch),
    curl_error($ch),
    $response
]);

curl_close($ch);
joedixon commented 5 months ago

Do you get any issue connecting to the WebSocket server over wss?

rasmus0201 commented 5 months ago

Hi - thanks for the quick response!

Yesterday I was able to connect to wss just fine with the sanctum auth also working. But this morning it appears it doesn't work...

Further setup details:

I'm currently having Vite proxy https://localhost:5173/api/* to http://127.0.0.1:8000/api/*

Don't know if it has something to do with the proxy, but just weird that I get the same response/error when using a php test script (as you can see in the issue description).

Now trying to connect with wss I get:

$ websocat wss://localhost:8080/app/sdzhejnkcsrwunmyikgh -v --origin=https://localhost:5173
[INFO  websocat::lints] Auto-inserting the line mode
[INFO  websocat::stdio_threaded_peer] get_stdio_peer (threaded)
[INFO  websocat::ws_client_peer] get_ws_client_peer
websocat: WebSocketError: I/O failure
websocat: error running

or in browser: use-ws.ts:39 WebSocket connection to 'wss://localhost:8080/app/sdzhejnkcsrwunmyikgh?protocol=7&client=js&version=8.3.0&flash=false' failed:

When disabling TLS for the reverb server it seems that I can connect (but only using IP?):

$ websocat ws://127.0.0.1:8080/app/sdzhejnkcsrwunmyikgh -v --origin=https://localhost:5173
[INFO  websocat::lints] Auto-inserting the line mode
[INFO  websocat::stdio_threaded_peer] get_stdio_peer (threaded)
[INFO  websocat::ws_client_peer] get_ws_client_peer
[INFO  websocat::ws_client_peer] Connected to ws
{"event":"pusher:connection_established","data":"{\"socket_id\":\"227535699.117823784\",\"activity_timeout\":30}"}

(using localhost yield the same WebSocketError: I/O failure)

Trying my test script without TLS/HTTPS - which successfully works:

int(0)
string(0) ""
string(228) "{"name":["The name field is required."],"data":["The data field is required."],"channels":["The channels field is required when channel is not present."],"channel":["The channel field is required when channels is not present."]}"

Though here it doesn't matter if it is curl_setopt($ch, CURLOPT_URL, "http://127.0.0.1:8080/apps/468562/events"); or curl_setopt($ch, CURLOPT_URL, "http://localhost:8080/apps/468562/events");

So I'm a bit lost at what the issue really seems to be. Maybe something with the reverb http server in combination with using a custom SSL certificate (not using valet/herd).

Lastly I've also just tried a different hostname pp.localhost without TLS, that also seems to work (but not using websocat with the hostname 😅 ).

joedixon commented 5 months ago

There's a lot going on here, so quite difficult to debug. However, what happens if you try to hit https://127.0.0.1/app/sdzhejnkcsrwunmyikgh directly in the browser?

rostamsodagari commented 5 months ago

Hello every body.

I still have the same problem and I am using Laravel 10 with Valet. I set local_cert and local_pk inside configuration file. Also verify_peer has been set on false. I got Internal Server Error while calling (https://domain.test:8080/app/uxgvldvjgvcc0rnnsuac).

joedixon commented 5 months ago

Can you share a screenshot of the error?

driesvints commented 5 months ago

Gonna close this one now. Feel free to open a new issue if you still experience this.

muresanandrei commented 5 months ago

I have the same issue why close this when it is not fixed.

volkeransmann commented 5 months ago

Same here on a brand new installation. Laravel 11.3.1, PHP 8.3.6. Whats especially weird is that the broadcast happens. So a listener on a different page gets it. Of course the page that triggers the dispatch still gets the error.

muresanandrei commented 5 months ago

@volkeransmann In my case issue was using valet with secure reverb. Just using herd fixed the OpenSSL error. Seems to be an issue with valet certificates for some reason.

volkeransmann commented 5 months ago

@muresanandrei thanks for the tip. But that did non work in my case. Still getting the same error.