`FrameSizeException` when requesting non-TLS hosts
- https://github.com/cfug/dio/pull/2220#issuecomment-2118544840
- https://github.com/cfug/dio/actions/runs/9135981572/job/25124169253?pr=2220
Steps to reproduce
- Clone https://github.com/cfug/dio and enter the directory.
melos bs.- Run the test with
plugins/http2_adapter/test/test_suite_test.dart.
When increasing the max frame size to 1 << 24, another exception was thrown: FrameSizeException: Incoming byte stream ended with incomplete frame.
This typically happens when the destination is trying to redirect from a non-TLS to a TLS URL.
@mosuem
Did someone have insights about the cause of the issue and workarounds?
Also FYI @brianquinlan
I think that @mosuem is the HTTP2 expert.
I am very far from an HTTP expert, but I am the maintainer of this library. I am reading into this. The issue is HTTP->HTTP2 redirect handling in this library, correct?
I am reading into this. The issue is HTTP->HTTP2 redirect handling in this library, correct?
So far it does.
I am not familiar with the linked dio library - an example in package:http2 of what type of request you are trying to perform would help, and what the expected behavior is.
Oh sure sorry for the inconvenience. I'll bring up a reproducible example with the package only sooner or later next week.
Set a breakpoint at:
https://github.com/dart-lang/http/blob/531d3e587c3214ad07bed1f52fac3f01112bc1ed/pkgs/http2/lib/src/connection.dart#L167
Then debug the below example, also change the if (transport is ClientConnection) branch to see different types of FrameSizeException.
import 'dart:convert';
import 'dart:io';
import 'package:http2/http2.dart';
import 'package:http2/src/connection.dart' show ClientConnection;
void main() async {
final uri = Uri.parse('http://pub.dev/');
final transport = ClientTransportConnection.viaSocket(
await Socket.connect(
uri.host,
uri.port,
),
);
// Without the below [maxFrameSize] increment, "Incoming frame is too big" will be thrown.
// With the below manipulation, "Incoming byte stream ended with incomplete frame" will be thrown.
if (transport is ClientConnection) {
transport.acknowledgedSettings.maxFrameSize = 1 << 24;
}
final stream = transport.makeRequest(
[
Header.ascii(':method', 'GET'),
Header.ascii(':path', uri.path),
Header.ascii(':scheme', uri.scheme),
Header.ascii(':authority', uri.host),
],
endStream: true,
);
await for (final message in stream.incomingMessages) {
if (message is HeadersStreamMessage) {
for (final header in message.headers) {
final name = utf8.decode(header.name);
final value = utf8.decode(header.value);
print('Header: $name: $value');
}
} else if (message is DataStreamMessage) {
// Use [message.bytes] (but respect 'content-encoding' header)
}
}
await transport.finish();
}
I get a Unhandled exception: HTTP/2 error: Connection error: Connection is being forcefully terminated. (errorCode: 10) when using your example. It does work when switching to SecureSocket.connect, as in the HTTP2 example.
I get a
Unhandled exception: HTTP/2 error: Connection error: Connection is being forcefully terminated. (errorCode: 10)when using your example.
You need to set a debug point like my previous comment which is the underlying exception.
It does work when switching to
SecureSocket.connect, as in the HTTP2 example.
Should we use SecureSocket regardless of TLS?
You need to set a debug point like my previous comment which is the underlying exception.
Ah right, now I understand. Let me check.