flutterdartwebsocketproxy

Inspect WebSocket packages with Charles proxy in Flutter app


I'm developing mobile application using Flutter/Dart. What I need is to debug/test my application's network traffic with Charles proxy/Fiddler. It's easy to inspect http requests/responses in dart/flutter using Charles proxy. We only need to tell HttpClient an address of proxy server (IP address of machine where Charles is installed) like this:

final client = HttpClient();
client.findProxy = (uri) {
  String proxy = '1.2.3.4:8888';
  return "PROXY $proxy;";
};
client.badCertificateCallback =
  ((X509Certificate cert, String host, int port) => Platform.isAndroid);

But how can I debug WebSocket traffic created via WebSocket.connect('wss://server_address');? WebSocket doesn't have any api for setting proxy settings and I couldn't find anything on forums. That being said, I already did such things in the past in another mobile app written on C# and it was pretty easy.


Solution

  • Figured it out. There are actually multiple ways to do that:

    Global Proxy settings:

    class ProxiedHttpOverrides extends HttpOverrides {
      String _proxy;
      ProxiedHttpOverrides(this. _proxy);
    
      @override
      HttpClient createHttpClient(SecurityContext? context) {
        return super.createHttpClient(context)
          ..findProxy = (uri) {
            return _proxy.isNotEmpty ? "PROXY $_proxy;" : 'DIRECT';
          }
          ..badCertificateCallback = (X509Certificate cert, String host, int port) => Platform.isAndroid;
      }
    }
    
    void main() {
      String proxy = '1.2.3.4:8888';
      HttpOverrides.global = new ProxiedHttpOverrides(proxy);
      runApp(MyApp());
    }
    

    Custom HttpClient passed into WebSocket.connect

    HttpClient client = HttpClient();
      client.findProxy = (uri) => "PROXY $proxy;";
      client.badCertificateCallback = (X509Certificate cert, String host, int port) => Platform.isAndroid;
    
    WebSocket.connect(url, customClient: client);
    

    Manual way: We need to upgrade to WebSocket using simple HttpClient with specified proxy settings. In that case we will be able to inspect WebSocket traffic in Charles/Fiddler.

    Future<WebSocket> createProxySocket() async {
      String url = 'https://echo.websocket.org:443';//address must start from http(s)://, not from ws(s)://, as we are connecting using http
      String proxy = '1.2.3.4:8888';//your machine address (or localhost if debugging on the same machine)
      Random r = new Random();
      String key = base64.encode(List<int>.generate(8, (_) => r.nextInt(255)));
    
      HttpClient client = HttpClient();
      client.findProxy = (uri) => "PROXY $proxy;";
      client.badCertificateCallback = (X509Certificate cert, String host, int port) => Platform.isAndroid;
    
      Uri uri = Uri.parse(url);
      HttpClientRequest request = await client.getUrl(uri);
      request.headers.add('Connection', 'upgrade');
      request.headers.add('Upgrade', 'websocket');
      request.headers.add('Sec-WebSocket-Version', '13');
      request.headers.add('Sec-WebSocket-Key', key);
    
      HttpClientResponse response = await request.close();
      Socket socket = await response.detachSocket();
    
      return WebSocket.fromUpgradedSocket(socket, serverSide: false);
    }