Inspect WebSocket packages with Charles proxy in Flutter app

621

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);
}
Share:
621
Shpand
Author by

Shpand

Updated on January 03, 2023

Comments

  • Shpand
    Shpand over 1 year

    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.