ProxymanApp / Proxyman

Modern. Native. Delightful Web Debugging Proxy for macOS, iOS, and Android ⚡️
https://proxyman.io
5.65k stars 186 forks source link

Feature Request: Web socket support #1521

Open alexsm20 opened 1 year ago

alexsm20 commented 1 year ago

Description

Web socket support.

Why this feature/change is important?

We can stop using Charles (which can be unreliable) and start buying licenses from you instead.

NghiaTranUIT commented 1 year ago

Websocket (WS/WSS) is already supported. You can check out the Doc at https://docs.proxyman.io/advanced-features/websocket

If you means Websocket from iOS app, you should use Atlantis framework (https://github.com/ProxymanApp/atlantis) because URLWebsocketTask doesn't go through the Proxy by default. It's a known issues from Apple.

sgade commented 9 months ago

I just stumbled across this issue myself. We are using web sockets for Apollo (GraphQL) subscriptions. I wrote a custom client implementation using URLSessionWebSocketTask but still didn't see the data.

The documentation states that:

From iOS 17 and macOS 14, Proxyman can capture WS/WSS from URLSessionWebSocketTask out of the box. No need to use the Atlantis framework.

Is that only for physical devices? I couldn't get it to work in the simulator without the Atlantis framework. If so, the documentation should clarify that.

NghiaTranUIT commented 9 months ago

I tested with iOS Simulator, with a URLSessionWebSocketTask, no Atlantis and it just works fine with a sample iOS 17 project.

https://github.com/ProxymanApp/Proxyman/assets/5878421/aee6db98-7655-40c7-89bd-a4a5b622ee5d


We are using web sockets for Apollo (GraphQL) subscriptions

I guess you're using this one: https://github.com/apollographql/apollo-ios/tree/main

I believe that Apollo doesn't use native URLSessionWebsocket, they use Input/OutputStream that doesn't support HTTP Proxy

Ref: https://github.com/apollographql/apollo-ios/blob/6bdaf4eb46312dfc7ccefc9f683dc42d1db257b5/Sources/ApolloWebSocket/DefaultImplementation/WebSocketStream.swift#L47

However, they support SOCKS Proxy: https://github.com/apollographql/apollo-ios/blob/6bdaf4eb46312dfc7ccefc9f683dc42d1db257b5/Sources/ApolloWebSocket/DefaultImplementation/WebSocketStream.swift#L20

  1. Open Proxyman -> Tools -> Proxy Setting -> Enable SOCKS Proxy at port 8889
  2. Provides a custom SOCKS Proxy to your Apollo library
  3. Proxyman will capture the WS/WSS from Apollo
sgade commented 9 months ago

Thanks for taking the time to look into this, @NghiaTranUIT!

Yes, Apollo is shipping their own WebSocket implementation which is using the WebSocketStream you linked. However, the former is used as the default implementation for the WebSocketClient which I replaced with an implementation using URLSessionWebSocketTask as the underlying system. And it didn't show up in Proxyman either.

Adding Atlantis, it worked instantly. Switching back to the WebSocket by Apollo expectedly made it disappear from Proxyman again. So that is why I am wondering why it didn't work out-of-the-box as advertised.

What is that example app you are showing there? It doesn't seem to be the Atlantis example project.

NghiaTranUIT commented 9 months ago

Thanks. I will write an example with URLSessionWebsocket and use Proxyman to capture (without using the Atlantis framework) and get back to you soon.


If Atlantis works for you, I recommend using it.

Websocket is quite tricky on iOS, even with Charles Proxy, it might not be able to capture it (if not using Atlantis)

NghiaTranUIT commented 9 months ago

@sgade I confirmed that Proxyman can capture URLSessionWebsocketTask out of the box (No Atlantis framework).

iOS Simulator

Proxyman captures websocket from iOS Simulator

iOS Device

sgade commented 9 months ago

Thank you for the example project. I was doing everything the same except for using a different overload of webSocketTask(with:). This one accepts a URLRequest instead of a URL. According to Apple's documentation one can use this to set custom headers on the request.

The result with this is call that Proxyman does not show the request at all. Replacing the call with the request.url! instantly makes it show up in Proxyman.

To reproduce this issue in your example project, replace the URL with a URLRequest in ViewController.swift:30:

//      return session.webSocketTask(with: URL(string: "wss://ws.postman-echo.com/raw")!)
        return session.webSocketTask(with: URLRequest(url: URL(string: "wss://ws.postman-echo.com/raw")!))
NghiaTranUIT commented 9 months ago

In this case, I guess it's a bug from URLSessionWebsocketTask. If It's a bug from Proxyman, the WS connection must be failed.

Let me find a solution to make it work with URLRequest.

NghiaTranUIT commented 9 months ago

@sgade confirmed that URLSessionWebsocketTask doesn't work if using URLRequest. I tried to add Proxy Config to URLSessionConfiguration (HTTPSProxy and SOCKSProxy are not available on iOS), and it didn't work either.

I believe that it's intended by Apple. The only solution is to use Atlantis 👍

sgade commented 9 months ago

@NghiaTranUIT thank you for confirming!

NghiaTranUIT commented 9 months ago

@sgade if you find any solution, please let me know. I will bring it to Proxyman. For now, the only solution I know is using Atlantis.

Or using the SOCKSProxy setting in apollo-ios.

Ref: https://github.com/apollographql/apollo-ios/blob/6bdaf4eb46312dfc7ccefc9f683dc42d1db257b5/Sources/ApolloWebSocket/DefaultImplementation/WebSocketStream.swift#L20

rakeshkarkare commented 3 months ago

I tested with iOS Simulator, with a URLSessionWebSocketTask, no Atlantis and it just works fine with a sample iOS 17 project.

CleanShot.2023-12-04.at.21.32.15.mp4

We are using web sockets for Apollo (GraphQL) subscriptions

I guess you're using this one: https://github.com/apollographql/apollo-ios/tree/main

I believe that Apollo doesn't use native URLSessionWebsocket, they use Input/OutputStream that doesn't support HTTP Proxy

Ref: https://github.com/apollographql/apollo-ios/blob/6bdaf4eb46312dfc7ccefc9f683dc42d1db257b5/Sources/ApolloWebSocket/DefaultImplementation/WebSocketStream.swift#L47

However, they support SOCKS Proxy: https://github.com/apollographql/apollo-ios/blob/6bdaf4eb46312dfc7ccefc9f683dc42d1db257b5/Sources/ApolloWebSocket/DefaultImplementation/WebSocketStream.swift#L20

  1. Open Proxyman -> Tools -> Proxy Setting -> Enable SOCKS Proxy at port 8889
  2. Provides a custom SOCKS Proxy to your Apollo library
  3. Proxyman will capture the WS/WSS from Apollo

Hi @NghiaTranUIT I am getting responses from websocket as similar to yours. Is there any way to mock the responses in proxyman ? Could you please share some hints

NghiaTranUIT commented 3 months ago

Sorry, Mock Websocket response hasn't been supported yet. Only Mock a HTTP(S) Response works.

NghiaTranUIT commented 3 months ago

FYI, if you're using iOS 17 or later, Apple has fixed this problem. Proxyman can now capture WS/WSS from URLSessionWebsocketTask with the following config.