Skip to content

Commit

Permalink
Validate method name passed to HttpClient.open/openUrl (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexV525 committed Nov 6, 2022
1 parent ba716ca commit 927f79e
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 0 deletions.
54 changes: 54 additions & 0 deletions dio/lib/src/dio_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,34 @@ abstract class DioMixin implements Dio {
}
}

bool _isValidToken(String token) {
_checkNotNullable(token, "token");
// from https://www.rfc-editor.org/rfc/rfc2616#page-15
//
// CTL = <any US-ASCII control character
// (octets 0 - 31) and DEL (127)>
// separators = "(" | ")" | "<" | ">" | "@"
// | "," | ";" | ":" | "\" | <">
// | "/" | "[" | "]" | "?" | "="
// | "{" | "}" | SP | HT
// token = 1*<any CHAR except CTLs or separators>
const _validChars = r" "
r" ! #$%&' *+ -. 0123456789 "
r" ABCDEFGHIJKLMNOPQRSTUVWXYZ ^_"
r"`abcdefghijklmnopqrstuvwxyz | ~ ";
for (int codeUnit in token.codeUnits) {
if (codeUnit >= _validChars.length ||
_validChars.codeUnitAt(codeUnit) == 0x20) {
return false;
}
}
return true;
}

Future<Stream<Uint8List>?> _transformData(RequestOptions options) async {
if (!_isValidToken(options.method)) {
throw ArgumentError.value(options.method, "method");
}
var data = options.data;
List<int> bytes;
Stream<List<int>> stream;
Expand Down Expand Up @@ -830,3 +857,30 @@ abstract class DioMixin implements Dio {
return response;
}
}

/// A null-check function for function parameters in Null Safety enabled code.
///
/// Because Dart does not have full null safety
/// until all legacy code has been removed from a program,
/// a non-nullable parameter can still end up with a `null` value.
/// This function can be used to guard those functions against null arguments.
/// It throws a [TypeError] because we are really seeing the failure to
/// assign `null` to a non-nullable type.
///
/// See http://dartbug.com/40614 for context.
T _checkNotNullable<T extends Object>(T value, String name) {
if ((value as dynamic) == null) {
throw NotNullableError<T>(name);
}
return value;
}

/// A [TypeError] thrown by [_checkNotNullable].
class NotNullableError<T> extends Error implements TypeError {
NotNullableError(this._name);

final String _name;

@override
String toString() => "Null is not a valid value for '$_name' of type '$T'";
}
20 changes: 20 additions & 0 deletions dio/test/options_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -301,4 +301,24 @@ void main() {
final textResponse2 = await dio.get<String>('/test-force-convert');
expect(textResponse2.data, json.encode(expectedResponseData));
});

test('Throws when using invalid methods', () async {
final dio = Dio();
void testInvalidArgumentException(String method) async {
await expectLater(
dio.fetch(RequestOptions(path: 'http://127.0.0.1', method: method)),
throwsA((e) => e is DioError && e.error is ArgumentError),
);
}

const String separators = "\t\n\r()<>@,;:\\/[]?={}";
for (int i = 0; i < separators.length; i++) {
String separator = separators.substring(i, i + 1);
testInvalidArgumentException(separator);
testInvalidArgumentException(separator + "CONNECT");
testInvalidArgumentException("CONN" + separator + "ECT");
testInvalidArgumentException("CONN" + separator + separator + "ECT");
testInvalidArgumentException("CONNECT" + separator);
}
});
}

0 comments on commit 927f79e

Please sign in to comment.