http icon indicating copy to clipboard operation
http copied to clipboard

`FrameSizeException` when requesting non-TLS hosts

Open AlexV525 opened this issue 1 year ago • 3 comments

  • https://github.com/cfug/dio/pull/2220#issuecomment-2118544840
  • https://github.com/cfug/dio/actions/runs/9135981572/job/25124169253?pr=2220

Steps to reproduce

  1. Clone https://github.com/cfug/dio and enter the directory.
  2. melos bs.
  3. Run the test with plugins/http2_adapter/test/test_suite_test.dart.

AlexV525 avatar May 18 '24 01:05 AlexV525

When increasing the max frame size to 1 << 24, another exception was thrown: FrameSizeException: Incoming byte stream ended with incomplete frame.

AlexV525 avatar May 18 '24 01:05 AlexV525

This typically happens when the destination is trying to redirect from a non-TLS to a TLS URL.

AlexV525 avatar May 18 '24 02:05 AlexV525

@mosuem

AlexV525 avatar May 31 '24 09:05 AlexV525

Did someone have insights about the cause of the issue and workarounds?

AlexV525 avatar Dec 30 '24 02:12 AlexV525

Also FYI @brianquinlan

AlexV525 avatar Dec 30 '24 02:12 AlexV525

I think that @mosuem is the HTTP2 expert.

brianquinlan avatar Dec 30 '24 18:12 brianquinlan

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?

mosuem avatar Jan 02 '25 10:01 mosuem

I am reading into this. The issue is HTTP->HTTP2 redirect handling in this library, correct?

So far it does.

AlexV525 avatar Jan 02 '25 11:01 AlexV525

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.

mosuem avatar Jan 02 '25 11:01 mosuem

Oh sure sorry for the inconvenience. I'll bring up a reproducible example with the package only sooner or later next week.

AlexV525 avatar Jan 02 '25 15:01 AlexV525

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();
}

AlexV525 avatar Jan 11 '25 08:01 AlexV525

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.

mosuem avatar Feb 11 '25 15:02 mosuem

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?

AlexV525 avatar Feb 11 '25 15:02 AlexV525

You need to set a debug point like my previous comment which is the underlying exception.

Ah right, now I understand. Let me check.

mosuem avatar Feb 11 '25 15:02 mosuem