http
http copied to clipboard
Make SocketException catchable
You can check if that fixes everything, but for me it worked as expected. Before I had the annoying issue that my app would crash completely without any try-catch etc. helping in any way if my phone was simply offline. Now I can catch the SocketException with the try-catch around my http.get.
Future<User> getMe() async {
try {
final http.Response response = await http.get(
baseUrl + "user/",
headers: await defaultHeaders,
);
print("getMe: ${json.decode(utf8.decode(response.bodyBytes))}");
if (response.statusCode == 200) {
return User.fromJson(json.decode(utf8.decode(response.bodyBytes)));
} else {
String errorMsg =
Error.fromJson(json.decode(utf8.decode(response.bodyBytes)))
.message;
return Future.error(errorMsg);
}
} catch (e) {
print("getMe: $e");
// THIS IS WHERE THE SOCKETEXCEPTION IS CATCHED
return Future.error(_prepareError(e));
}
}
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).
:memo: Please visit https://cla.developers.google.com/ to sign.
Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.
What to do if you already signed the CLA
Individual signers
- It's possible we don't have your GitHub username or you're using a different email address on your commit. Check your existing CLA data and verify that your email is set on your git commits.
Corporate signers
- Your company has a Point of Contact who decides which employees are authorized to participate. Ask your POC to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the Google project maintainer to go/cla#troubleshoot (Public version).
- The email used to register you as an authorized contributor must be the email used for the Git commit. Check your existing CLA data and verify that your email is set on your git commits.
- The email used to register you as an authorized contributor must also be attached to your GitHub account.
ℹ️ Googlers: Go here for more info.
@googlebot I singed it!
I would not expect any of these changes to make a meaningful difference to the exceptions you are able to catch.
Can you give a specific narrow reproduction case where this changes behavior?
Sure, I think I already did. But it should be an issue with every http-request sent. If I put my phone offline via firewall (not by disabling WiFi) and use the non-forked version of http, the whole app crashes with a SocketException that was uncatched. I tried a lot in my own code until I looked into http and changed the things I changed for that PR. :D The SocketException was thrown deeper in http and not correctly pushed up to where I could catch it with the provided try-catch I put in the PR as an example.
The SocketException was thrown deeper in http and not correctly pushed up to where I could catch it
I'm not able to see that happen. Here is what I tried:
import 'package:http/http.dart' as http;
void main() async {
try {
await http.get(Uri.http('www.google.com', ''));
} catch (e) {
print('Caught: $e');
}
print('Done');
}
I disabled wifi and ran this with the VM. The output was:
Caught: SocketException: Failed host lookup: 'www.google.com' (OS Error: nodename nor servname provided, or not known, errno = 8)
Done
I am able to catch the exception without applying the diff in this PR.
I don't know how to reproduce the behavior you are seeing. And I would not expect that the changes in this diff would have any impact on the behavior of this package.
@natebosch I am having the same issue. http on MacOS desktop. You can reproduce by trying to do a http.post while wifi is off on the laptop. I am unable to catch the error even though I try.
I am experiencing the issue this pull request aims to solve.
This is related to issue #551. In my case I am connecting directly to an ip address over https on the local network. My wifi is on, but the ip in question doesn't exist and thus isn't routable. The socket exception gets reported but never manages to hit the catch block.
@0xNF - do you have a minimal reproduction you can share? I have not been able to see locally a SocketException which escapes a catch
@natebosch I came across the same issue today. I havent tested the solution provided with this MR,
but here's a sample Code which causes the exception:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<void> _doLoadStuff() async {
try {
String resBody = (await http
.get(Uri.parse("http://192.168.2.111/test"))
.timeout(Duration(seconds: 3)))
.body;
print(resBody);
} catch (ex) {
print(ex);
}
}
@override
void initState() {
_doLoadStuff();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Text("Hello World")],
),
),
);
}
}
The Exception will throw even after the timeout exception has been raised (just wait a few moments..). I used the latest http version:
name: http_issue
description: A new Flutter project.
publish_to: "none"
version: 1.0.0+1
environment:
sdk: ">=2.14.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
http: ^0.13.4
# ...
Flutter doctor output:
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.5.2, on Ubuntu 20.04.3 LTS 5.11.0-37-generic, locale de_DE.UTF-8)
[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
✗ cmdline-tools component is missing
Run `path/to/sdkmanager --install "cmdline-tools;latest"`
See https://developer.android.com/studio/command-line for more details.
✗ Android license status unknown.
Run `flutter doctor --android-licenses` to accept the SDK licenses.
See https://flutter.dev/docs/get-started/install/linux#android-setup for more details.
[✓] Chrome - develop for the web
[✓] Android Studio (version 3.5)
[✓] Android Studio (version 2020.3)
[✓] VS Code (version 1.60.2)
[✓] Connected device (2 available)
I used the Android Emulator to debug this.
See 484274785 which includes a code sample putting a .catchError before the .timeout to catch the SocketException.
I'll close this PR for now since it does not make a meaningful difference about what exceptions can be caught.