http icon indicating copy to clipboard operation
http copied to clipboard

Multipart request headers must be Camel-Case not lower-case. Or at least provide some way to specify it

Open alexcmgit opened this issue 2 years ago • 1 comments

Please describe the bug and how to reproduce it.

I ran into a trouble using http package when I was consuming an API because the http package is using lower-case headers.

The RFC specification says headers must be case-insensitive, but some third-party services are implemented in a case-sensitive way.

A example service running this way is AnonFiles.com, and here is a reproducible example:

import 'dart:io';
import 'dart:typed_data';

import 'package:http/http.dart' as http;

class MyHttpoverrides extends HttpOverrides {
  @override
  HttpClient createHttpClient(SecurityContext? context) {
    return super.createHttpClient(context)
      ..badCertificateCallback =
          (X509Certificate cert, String host, int port) => true;
  }
}

void main() async {
  // To debug with HTTP Toolkit
  HttpOverrides.global = MyHttpoverrides();

  var request = http.MultipartRequest(
    'POST',
    Uri.parse('https://api.anonfiles.com/upload'),
  );

  request.files.add(
    http.MultipartFile.fromBytes(
      'file',
      Uint8List.fromList(
        List<int>.filled(50, 0),
      ),
      filename: 'file',
    ),
  );

  http.StreamedResponse response = await request.send();

  if (response.statusCode == 200) {
    print(await response.stream.bytesToString());
  } else {
    print(response.reasonPhrase);
  }
}

This will fail with status code 400.

But if you modify the line multipart_request.dart#L135 by replacing:

-        'content-disposition: form-data; name="${_browserEncode(file.field)}"';
+        'Content-Disposition: form-data; name="${_browserEncode(file.field)}"';

You'll see the request will return 200 OK.

Although I agree that this is implementation error in the API side, I would appreciate a mechanism in this library that I can use to work around these issues since I've 0 control over the mentioned service.


This is the installed dependency version:

http:
    dependency: "direct main"
    description:
      name: http
      sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
      url: "https://pub.dev"
    source: hosted
    version: "0.13.6"

Although it's not the latest version, the code I mentioned as containing the lower-cased headers is still present in the latest v1.0.0 version.

alexcmgit avatar Jun 19 '23 03:06 alexcmgit

I also faced issues due to the 'content-disposition' string being in lowercase. While most APIs handle it without any problems, there can be cases where developers need more flexibility in handling it.

During my testing with 'dio', I discovered the 'camelCaseContentDisposition' option in the 'FormData' settings. It allowed me to address the problem caused by the lowercase 'content-disposition' string.

FormData.fromMap(
    Map<String, dynamic> map, [
    ListFormat collectionFormat = ListFormat.multi,
    this.camelCaseContentDisposition = true,
  ])

It would be great if the 'MultipartRequest' in 'http' could also provide an option to set the 'content-disposition' string to to 'Content-Disposition'.

sunbowkh avatar Jun 23 '23 04:06 sunbowkh