Code Monkey home page Code Monkey logo

Comments (13)

dsrees avatar dsrees commented on September 17, 2024 1

@msandel6 @nathanl Looking into this a little deeper and I found an issue with how the Client is passing errors back through onError. Reading the docs revealed this about didCompleteWithError

The only errors your delegate receives through the error parameter are client-side errors, such as being unable to resolve the hostname or connect to the host. To check for server-side errors, inspect the response property of the task parameter received by this callback.

In order to get the 401 from the server response, the client needs to return back the task.response to the calling code as well which should inform you of any potential server-side errors. I'm going to work on getting this added today. Hopefully that will help with whatever solution you guys came to.

from swiftphoenixclient.

dsrees avatar dsrees commented on September 17, 2024

Are you looking for socket.onOpen()?

from swiftphoenixclient.

msandel6 avatar msandel6 commented on September 17, 2024

.onOpen() is called from within that same URLSession delegate method, so unless I'm missing something that would be called under the same circumstances. 🤔

from swiftphoenixclient.

dsrees avatar dsrees commented on September 17, 2024

I'm sorry, i'm not 100% following what the problem exactly is that you're trying to solve for. Is there a different method that URLSession delegate provides that, if used, solves your usecase?

from swiftphoenixclient.

msandel6 avatar msandel6 commented on September 17, 2024

The problem is that the didOpenWithProtocol delegate method gets called after a successful TCP handshake, rather than after the socket is actually opened.

In my case, this is the sequence of events:

  1. I send the open request with parameters
  2. The server receives it (after successful handshake)
  3. The didOpenWithProtocol delegate callback happens due to the successful handshake
  4. The SwiftPhoenixClient framework sets socket.isConnected to true and calls socket.onOpen(). My app responds accordingly, entering a flow that assumes the socket is open.
  5. The server rejects the request to upgrade the connection to a socket if the parameters/credentials I sent are incorrect

The app now thinks there is an open socket connection, even though the socket was never opened.

Unfortunately, it doesn't look like there are other URLSessionWebSocketDelegate methods we can use to determine when a socket has actually been opened. Maybe there is a possible workaround using pings where at least one pong has to be returned before the socket is declared as isConnected, but I haven't had time to experiment with that.

from swiftphoenixclient.

dsrees avatar dsrees commented on September 17, 2024

Okay, i'm following now. Thank you for clarifying. I can't speak directly to the solution, but I would assume your server can allow the upgrade to the websocket but then proceed to close the connection with an error? I don't think there is anything client side to intercept a failed upgraded handshake

from swiftphoenixclient.

nathanl avatar nathanl commented on September 17, 2024

@dsrees From a Phoenix perspective, preventing the upgrade for failed authentication is a supported feature:

To deny connection, return :error or {:error, term}. To control the response the client receives in that case, define an error handler in the websocket configuration.
https://hexdocs.pm/phoenix/1.7.0-rc.2/Phoenix.Socket.html#c:connect/2-socket-params-and-assigns

Looks like we can do it at the channel layer too, but I think the normal use case there is like "you're allowed to connect to the chat server (Socket) but you're not allowed to join this specific room (Channel)." For dealing with an authentication error ("we don't know who you are"), the Socket seems like a more correct place to deny the user.

We can work around this, I just wanted to give that perspective.

from swiftphoenixclient.

nathanl avatar nathanl commented on September 17, 2024

I don't think there is anything client side to intercept a failed upgraded handshake

This seems like a bug, doesn't it? If you don't get a 101 Swiching Protcols response but assume that it worked, does that mean you wouldn't get an error if you tried to establish a connection to a REST endpoint?

from swiftphoenixclient.

dsrees avatar dsrees commented on September 17, 2024

@nathanl @msandel6 thanks for some additional context. I believe URLSession handles the 101 Switching Protocols response internally and doesn't seem to expose that level of detail to the delegate.

Testing this against a local server, if I return :error from Socket.connect/3, then the client receives the error and attempts to reconnect, which is the same behavior I see the Phoenix JS client performing. This error will be passed to your app via socket.onError { error in ... } callback where you can inspect it further if you'd like. Inside of this socket.onError callback, socket.isConnected is returning false for me and URLSession:webSocketTask:didOpenWithProtocol: is never being called.

That all being said, I am not able to reproduce the same behavior described earlier:

  1. The didOpenWithProtocol delegate callback happens due to the successful handshake
  2. The SwiftPhoenixClient framework sets socket.isConnected to true and calls socket.onOpen(). My app responds accordingly, entering a flow that assumes the socket is open.

If you can create a small client/server repo that reproduces this error, then I'd be happy to look further into this. For reference, I am testing using the ChatRoomViewController found in the client's example project and this chat server locally.

from swiftphoenixclient.

msandel6 avatar msandel6 commented on September 17, 2024

@dsrees Thanks for the response! So when you return an error it never even enters the .onOpen delegate functions?
In my case the client error delegate does get hit (and .isConnected set to false), but only after first going through .onOpen and setting .isConnected to true. So I still can't rely on the .isConnected value unless I add an arbitrary wait time to ensure it isn't closely followed by an error.

from swiftphoenixclient.

dsrees avatar dsrees commented on September 17, 2024

@msandel6 that is correct. If you can reproduce it in a toy ios/phoenix project then I am happy to pull that and take a look.

from swiftphoenixclient.

msandel6 avatar msandel6 commented on September 17, 2024

Interesting. Makes sense to me, thanks so much for investigating @dsrees!

from swiftphoenixclient.

dsrees avatar dsrees commented on September 17, 2024

5.2.0 has been released with this fix. You can see it in action here

from swiftphoenixclient.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.