Skip to content

SecureSocket handshake can stall the main thread for long time #41519

Closed
@besthyhy

Description

@besthyhy

In my application, the SDK used before was 1.9 and everything worked fine. After upgrading to 1.12, android still works well, but ios will get stuck on the splash screen.

Detailed questions:

  1. Sometimes the first time you start it will get stuck on the splash screen.
  2. Manually kill the process and then enter the app, there is a high possibility that it will get stuck on the splash screen page.

Code situation

  1. pubspec.yaml
    http: 0.12.0+4
  2. lib/SplashPage.dart
class SplashPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _StdPageState();
  }
}

class _StdPageState extends State<SplashPage> {
  @override
  void initState() {
    super.initState();
    
    // send Http here
  }
}
  1. lib/util/HttpsUtils.dart
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:inlan_flutter/Config.dart';
import 'package:inlan_flutter/util/DataUtils.dart';
import 'package:inlan_flutter/util/I18nUtils.dart';
import 'package:inlan_flutter/util/JsonUtils.dart';
import 'package:inlan_flutter/util/LogUtils.dart';
import 'package:inlan_flutter/util/ToastUtils.dart';
import 'package:inlan_flutter/util/UpgradeUtils.dart';
import 'package:inlan_flutter/util/UuidUtils.dart';

class HttpsUtils {
  static void apiPostWithUrl(
      String url,
      Map<String, dynamic> body,
      BuildContext context,
      StackTrace callPositionStackTrace,
      State state,
      callback(json)) async {
    body["version"] = Config.apiVersion;
    body["httpId"] = UuidUtils.v4();
    body["lang"] = I18nUtils.languageCode();
    body["path"] = url;

    String fullUrl = Config.apiUrl + url;

    final apiClient = http.Client();

    try {
      await apiClient
          .post(fullUrl,
              headers: {"Content-Type": "application/json"},
              body: JsonUtils.encode(body))
          .then((response) {
        LogUtils.log(response.statusCode, StackTrace.current,
            tag: "statusCode");

        LogUtils.devLog(Config.apiUrl + url, callPositionStackTrace,
            tag: "apiUrl " + url);

        LogUtils.devLog(JsonUtils.prettyJson(body), callPositionStackTrace,
            tag: "req");

        LogUtils.devLog(
            JsonUtils.prettyStr(response.body), callPositionStackTrace,
            tag: "resp ${response.statusCode}");

        switch (response.statusCode) {
          case 200:
            callback(JsonUtils.parse(response.body));
            break;
          case 400:
            Map<String, dynamic> jsonObj = JsonUtils.parse(response.body);
            state.setState(() {
              ToastUtils.short(jsonObj["message"]);
            });
            break;
          case 401:
            Map<String, dynamic> jsonObj = JsonUtils.parse(response.body);
            state.setState(() {
              ToastUtils.withCallback(jsonObj["message"], () {
                DataUtils.setByService('login_data', '-1');
                DataUtils.setByService('isLogined', '-1');
                Navigator.pushNamedAndRemoveUntil(
                    context, '/account', (Route<dynamic> route) => false);
              });
            });
            break;
          case 403:
            break;
          case 406:
            UpgradeUtils().doForceUpgrade(context);
            break;
          case 422:
            Map<String, dynamic> jsonObj = JsonUtils.parse(response.body);
            state.setState(() {
              ToastUtils.short(jsonObj["message"]);
            });
            break;
        }
      });
    } finally {
      apiClient.close();
    }
  }
}

My temporary solution

  void initState() {
    super.initState();
    Timer timer = new Timer(new Duration(milliseconds: 1200), () {
      // send Http here
    });
    
  }

Expected solution

  1. What causes the freeze?
  2. A better solution?

Activity

tp

tp commented on Mar 5, 2020

@tp
Contributor

@besthyhy

We ran into the same issue. For us our the issue was caused by our "User-Agent overwrite" not working anymore with Flutter 1.12, which cause the server to respond with status 400.

Maybe providing some user-agent header (headers: {"User-Agent": "foo"}), would also fix your issue and obliviate the need for the timeout?

ghostgzt

ghostgzt commented on Mar 8, 2020

@ghostgzt

me too!
It is due to some https url!

beiger

beiger commented on Apr 9, 2020

@beiger

url: https://gank.io/api/v2/categories/Article
method: GET
my location: China

ios ui freeze on http request

lanistor

lanistor commented on Apr 9, 2020

@lanistor

Same issue. It's really a very very very terrible problem.
My environment:
http: v0.12.0+2 ~ 4
Dart: 2.8.0
Flutter: 1.15.3

Relative issues: dart-lang/http#400.

natebosch

natebosch commented on Apr 10, 2020

@natebosch
Member

Does this replicate when you use dart:io directly to make the request?

The comments so far don't give much to investigate - is this because there is a Future that does not resolve?

Does anyone have a minimal reproduction?

lanistor

lanistor commented on Apr 11, 2020

@lanistor

@natebosch In my case, i was using dart:io and package:http/http.dart at the same time in my one dart file, dart:io is used to add platform info to http headers.
After readed your words, i removed import dart:io line, it worked fine suddenly, and then i added import dart:io back, it works fine too, and the error cannot occour ever, even i run flutter clean to clean my build folder and run again. It' really wired.
Now i removed import dart:io just in case. But i really don't know why.

beiger

beiger commented on Apr 11, 2020

@beiger

If the website uses lets encrypt certification, the ui will be freeze on https request.
iOS platform
url: https://letsencrypt.org/
method: GET
use dart:io directly

natebosch

natebosch commented on Apr 13, 2020

@natebosch
Member

@vifird - the concern isn't having imports to dart:io in the same file - it is whether the suspected bug is caused by this package, or by dart:io. When you use package:http on mobile with flutter it is acting as a thin wrapper around HttpClient. When you use this package on the web it is a thin wrapper around HttpRequest. Usually when something fundamentally doesn't work it can be reproduced without using this package at all, but by using dart:io or dart:html directly. We ask for reproduction cases using these imports to help us route the bug to the right place. We can't solve any problem in this repository if the bug isn't caused by this repository.

@beiger - Can you get more specific? Is there a Future that should complete but doesn't? Does the entire runtime crash?

use dart:io directly

If you can reproduce without using this package we will need to route the issue to the Dart SDK repo. Do you have a complete and minimal reproduction case?

beiger

beiger commented on Apr 15, 2020

@beiger

@natebosch
This is my code:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:package_info/package_info.dart';

class AboutPage extends StatefulWidget {
 @override
 AboutPageState createState() => AboutPageState();
}

class AboutPageState extends State<AboutPage> {
 String _version = "";
 double _top = -20;

 @override
 Widget build(BuildContext context) {
  return Scaffold(
   appBar: AppBar(
    title: "about",
   ),
   body: Stack(
    children: <Widget>[
     AnimatedPositioned(
      duration: const Duration(milliseconds: 2000),
      curve: Curves.bounceOut,
      left: 0,
      top: _top,
      child: Container(
       width: MediaQuery.of(context).size.width,
       child: Center(
        child: Text(
         _version,
         style: TextStyle(
          fontSize: 28,
          color: Colors.blue,
          fontWeight: FontWeight.bold
         ),
        ),
       ),
      ),
     )
    ],
   ),
  );
 }

 @override
 void initState() {
  super.initState();
  _getVersion();
  test();
 }

 Future<void> test() async {
//  var url="https://gank.io/";  // Letsencrypt CA
  var url='https://github.com/dart-lang/http/issues/374'; // other certificate
  var httpClient = HttpClient();
  var request = await httpClient.getUrl(Uri.parse(url));
  var response = await request.close();
  print(response);
 }

 void _getVersion() {
  Future.delayed(Duration(microseconds: 500), () {
   PackageInfo.fromPlatform().then((value) {
    setState(() {
     _version =value.version;
     _top = MediaQuery.of(context).size.height / 2.7;
    });
   });
  });
 }
}

Letsencrypt CA url:
stuck

When you open this page, sometimes the page gets stuck in the middle, sometimes the animation gets stuck.

Other CA url:
The animation on the page is very smooth.

beiger

beiger commented on Apr 15, 2020

@beiger

Here is my iOS info:
image

There is no runtime crash.

natebosch

natebosch commented on Apr 15, 2020

@natebosch
Member

If the website uses lets encrypt certification, the ui will be freeze on https request.

Have you tried using an HttpClient from dart:io and setting the badCertificateCallback?

https://api.dart.dev/stable/2.7.2/dart-io/HttpClient/badCertificateCallback.html

natebosch

natebosch commented on Apr 15, 2020

@natebosch
Member

I think I'll move to the SDK repo for now. It's not entirely clear to me what the issue is, but I don't see any evidence it's related to package:http.

transferred this issue fromdart-lang/httpon Apr 15, 2020
beiger

beiger commented on Apr 16, 2020

@beiger

I'm using HttpClient from dart:io. I tried to set the badCertificateCallback, the program did not enter callback.

I've only had this kind of stuck situation since last month, and there are some people who have met earlier than me. It used to run well with the same code several month ago. This is only on IOS, Android is good.

mraleph

mraleph commented on Apr 23, 2020

@mraleph
Member

I don't think there is enough information here for us to diagnose problem.

HTTP processing is done asynchronously so it can't just block your UI thread.

I would start by looking for exceptions in the logs.

72 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1A high priority bug; for example, a single project is unusable or has many test failuresarea-vmUse area-vm for VM related issues, including code coverage, and the AOT and JIT backends.customer-flutterlibrary-iotype-bugIncorrect behavior (everything from a crash to more subtle misbehavior)

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @tp@mraleph@winterdl@cooolinx@aam

      Issue actions

        SecureSocket handshake can stall the main thread for long time · Issue #41519 · dart-lang/sdk