FormatException Invalid HTTP header Flutter on iOS - ios

This code work's on Android device and emulator perfectly. On iOS emulator, doesn't work.
I try change String to lower case, remove spaces, etc, nothing resolve.
import 'package:http/http.dart' show Client;
...
Map<String,String> headers = Map();
headers['device'] = 'appleiphonexʀ';//'Apple-iPhone-Xʀ'//'Apple_iPhone_Xʀ'//'Apple iPhone Xʀ'
...
var response = await client.get(Uri.parse(url), headers: headers);
return await processResponse(response);
Throws Exception:
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: FormatException: Invalid HTTP header field value: "appleiphonexʀ"
_HttpHeaders._validateValue (dart:_http/http_headers.dart:601:9)
_HttpHeaders._addAll (dart:_http/http_headers.dart:65:18)
_HttpHeaders.set (dart:_http/http_headers.dart:76:5)
IOClient.send.<anonymous closure> (package:http/src/io_client.dart:42:27)
__CompactLinkedCustomHashMap&_HashFieldBase&MapMixin&_LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:367:8)
IOClient.send (package:http/src/io_client.dart:41:23)
< asynchronous suspension>
BaseClient._sendUnstreamed (package:http/src/base_client.dart:169:38)
< asynchronous suspension>
BaseClient.post (package:http/src/base_client.dart:54:7)
NetworkProvider.post (package:PROJECTXX/src/models/resources/network_provider.dart:24:22)
<asynchronous suspension>
Solved: see answer

The last character in your header is the Unicode code point hex 0280 aka LATIN LETTER SMALL CAPITAL R. According to RFC 2616, HTTP headers must only include characters in ISO-8859-1, unless they are encoded in a MIME format, which might look like =?UTF-8?Q?=E2=9C=B0?=. Could you instead use lower or uppercase ASCII R?

Follow Richard Heap comment, the problem was the last character, this data came from lib device_info: ^0.4.0+1
final DeviceInfoPlugin deviceInfoPlugin = new DeviceInfoPlugin();
PackageInfo packageInfo = await PackageInfo.fromPlatform();
...
var device = await deviceInfoPlugin.iosInfo.name;//Apple iPhone Xʀ
...
//the solution: remove non ascii chars and substitute for underline
headers['device'] = device.replaceAll(new RegExp('[^\u0001-\u007F]'),'_');

Related

Unit Testing Exceptions in Dart/Flutter

I'm trying to unit test using the given code.
test('Given Employee When employeeName less than 5 then throws Exception', () async {
final employee = EmployeesCompanion.insert(
employeeName: 'Tony',
employeeCode: 'HR-121',
address: '5th Floor, Park Avenue',
contact: '1234567890',
hiringDate: DateTime.now());
expectLater(await employeesDB.createEmployee(employee),
throwsA((f) => f.toString().contains('employeeName: Must at least be 5 characters long')));
});
My unit test includes a predicate throwsA((f) => f.toString().contains('employeeName: Must at least be 5 characters long')) as given but dart fails this test with the exception:
package:moor/src/runtime/data_verification.dart 74:5 VerificationContext.throwIfInvalid
package:moor/src/runtime/query_builder/statements/insert.dart 197:51 InsertStatement._validateIntegrity
package:moor/src/runtime/query_builder/statements/insert.dart 96:5 InsertStatement.createContext
package:moor/src/runtime/query_builder/statements/insert.dart 64:17 InsertStatement.insert
package:moor_ex/src/db/employees.dart 79:76 EmployeesDB.createEmployee
test\employee_dept_test.dart 28:35 main.<fn>
InvalidDataException: Sorry, EmployeesCompanion(id: Value.absent(), employeeName: Value(Tony), employeeCode: Value(HR-121), address: Value(5th Floor, Park Avenue), contact: Value(1234567890), hiringDate: Value(2020-08-18 13:26:34.435349)) cannot be used for that because:
• employeeName: Must at least be 5 characters long.
So what's the correct way to write this test in Dart?
Try removing the await, or move it outside/before the expectLater.
The only difference between expect and expectLater is that the latter returns a future, but you ignore that future.
The expect/throwsA needs either a closure or a Future as the actual value, but you await that future so the await ... expression throws before you even call expectLater. Remove the await so you pass the Future to expectLater and the throwsA will then catch and match the error of that future.
So, I recommend changing it to:
await expectLater(employeesDB.createEmployee(employee), ...

Dart Higher-Order function with Generics

I'm trying to create a simple debug/print function that I can pipe through a sequence of then while processing Future results in Dart.
My function definition is as follows:
import 'dart:async';
typedef FutureOr<T> Pipe<T>(T pipeThrough);
Pipe<A> debug<A>(String log) {
return (A pipeThrough) {
print(log);
return pipeThrough;
};
}
It will return a function that just pipes through whatever it has received from the Future chain, and before that it will print the message log that has been sent to debug.
The way I'm using the function is quite simple:
Future<Map> load(String folder) {
return File(Paths.of([folder, 'data.json']))
.readAsString()
.then((s) => jsonDecode(s))
.then(debug<Map>('JSON LOADED!'));
}
As you can see in the last then in the future chain, it is supposed to return whatever was in the chain, but before that print 'JSON LOADED!'.
But there is something with the generics and Future api that I didn't manage to find a way to make it work, here's the error:
Unhandled exception:
type '(Map<dynamic, dynamic>) => Map<dynamic, dynamic>' is not a subtype of type '(dynamic) => FutureOr<Map<dynamic, dynamic>>'
#0 load (file:///{.../..../......}/data/data_json.dart:11:13)
#1 main (file:///{.../..../......}/data/main.dart:7:28)
#2 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
I've tried a bunch of different things, but fundamentally I don't get what's happening, doesn't dart infer the proper types based on the generic types annotation?
I don't know why it can't handle the type here, but changing the code to
Future<Map> load(String folder) {
return File(Paths.of([folder, 'data.json']))
.readAsString()
.then((s) => jsonDecode(s))
.then((v) => debug<Map>('JSON LOADED!')(v));
}
fixes your issue. I had thought that this should be equivalent...

Decoding JSON in dart

I have this simple dart file which I'm running:
import 'dart:convert';
// ...
dynamic test() {
final strJson = '{"ACB":["{\"date\":\"2020-02-28\",\"open\":1.36,\"close\":1.34,\"high\":1.4,\"low\":1.32,\"volume\":26469238}","{\"date\":\"2020-03-12\",\"open\":47.99,\"close\":45.54,\"high\":50.09,\"low\":45.37,\"volume\":50661745}"]}';
final parsedJson = json.decode(strJson);
print('${parsedJson.runtimeType} : $parsedJson');
}
main() {
test();
}
But getting this weird exception:
Unhandled exception:
FormatException: Unexpected character (at character 12)
{"ACB":["{"date":"2020-02-28","open":1.36,"close":1.34,"high":1.4,"low":1.3...
^
#0 _ChunkedJsonParser.fail (dart:convert-patch/convert_patch.dart:1394:5)
#1 _ChunkedJsonParser.parse (dart:convert-patch/convert_patch.dart:924:48)
#2 _parseJson (dart:convert-patch/convert_patch.dart:31:10)
#3 JsonDecoder.convert (dart:convert/json.dart:495:36)
#4 JsonCodec.decode (dart:convert/json.dart:153:41)
#5 test (file:///home/val/src/labs/maingain/test.dart:60:27)
#6 main (file:///home/val/src/labs/maingain/test.dart:65:3)
#7 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:307:19)
#8 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
I'll just say, that running similar code from the Flutter seems to work fine. Only when running this from command line give me the above.
Also validated JSON.
Put an r in front of the string literal.
The '{"ACB":["{\"date\":....' is a plain single-quoted Dart string literal. That means that backslash is a string escape, so \" only adds " to the string value.
It's not a necessary escape because the string uses single quotes, but it's still treated like an escape.
That means that you pass the string content {"ACB":["{"date":... to the JSON decoder, which promptly gives up because the code is not valid JSON.
If you put an r in front of the string: r'{"ACB":["{\"date\":...' then the string literal becomes a raw string. That means that backslashes do not work as escapes, but are treated like literal characters. That makes the resulting string valid JSON.
Another alternative is to change every backslash to two: '{"ACB":["{\\"date\\":...'.

How to parse json data if it has escape characters in response with dart or flutter?

my json response is {"quoteText":"You\'re not obligated to win. You\'re obligated to keep trying to do the best you can every day.", "quoteAuthor":"Marian Edelman"} and I am trying to decode by Map<String, dynamic> quoteData = jsonDecode(response.body); but getting this exception
[ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception:
E/flutter ( 5814): FormatException: Unrecognized string escape (at character 20)
E/flutter ( 5814): {"quoteText":"You\'re not obligated to win. You\'re obligated to keep tryin...
E/flutter ( 5814): ^
E/flutter ( 5814):
E/flutter ( 5814): #0 _ChunkedJsonParser.fail (dart:convert/runtime/libconvert_patch.dart:1358:5)
Tried by json.decode() and by doing flutter-remove-escape-sequence-in-dart but no luck. Any workaround?
That isn't valid json. Single quotes should not be escaped. Either you should get the source to fix it, or you can try to fix the string yourself by wholesale replacing any occurrence of \' with '.
String fixed = badString.replaceAll(r"\'", "'");
json.decode(fixed);

Constructing a ByteData view with a Uint8List throws an exception in Chrome

Chrome throws an exception when constructing a ByteData from a Uint8List.
Uncaught TypeError: First argument to DataView constructor must be an ArrayBuffer
I need to use a ByteBuffer in constructing the ByteData view but ByteBuffer is an abstract class. Here are the two lines where I construct a ByteData view. This works in the VM but not Chrome.
var buffer = new Uint8List(44);
var view = new ByteData.view(buffer);
Any idea how to fix this?
I tried your code and it worked
Dart VM version: 1.2.0-dev.3.0 (Fri Jan 31 02:47:34 2014) on "linux_x64"
but I think the correct way is:
var buffer = new Uint8List(44);
var view = new ByteData.view(buffer.buffer);
The first parameter of ByteData.view() is of type ByteBuffer and buffer.buffer returns a ByteBuffer. I don't know where the messages ArrayBuffer comes from.

Resources