mirror of
https://github.com/dart-lang/sdk
synced 2024-11-05 18:22:09 +00:00
[io/http] Validate method name passed to HttpClient.open/openUrl.
There should be no control characters or delimiters in method name provided to open/openUrl methods. Fixes https://github.com/dart-lang/sdk/issues/45744 TEST=http_open_method_validate_test Change-Id: I0db98f2376c980a054420fb447d4f7ef9321f1a9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256429 Reviewed-by: Siva Annamalai <asiva@google.com> Reviewed-by: Brian Quinlan <bquinlan@google.com> Commit-Queue: Alexander Aprelev <aam@google.com>
This commit is contained in:
parent
18e4b40dcc
commit
6abb6e5110
9 changed files with 115 additions and 11 deletions
|
@ -170,8 +170,8 @@ Evaluated: MapLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 ->
|
|||
Evaluated: SymbolLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> SymbolConstant(#noFolding)
|
||||
Evaluated: ListLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> ListConstant(const <Type*>[])
|
||||
Evaluated: MapLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> MapConstant(const <Symbol*, dynamic>{})
|
||||
Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:564:8 -> SymbolConstant(#clear)
|
||||
Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:564:8 -> ListConstant(const <Type*>[])
|
||||
Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:564:8 -> ListConstant(const <dynamic>[])
|
||||
Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:564:8 -> MapConstant(const <Symbol*, dynamic>{})
|
||||
Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:568:8 -> SymbolConstant(#clear)
|
||||
Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:568:8 -> ListConstant(const <Type*>[])
|
||||
Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:568:8 -> ListConstant(const <dynamic>[])
|
||||
Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:568:8 -> MapConstant(const <Symbol*, dynamic>{})
|
||||
Extra constant evaluation: evaluated: 268, effectively constant: 91
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
library dart._http;
|
||||
|
||||
import 'dart:_internal'
|
||||
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||
show
|
||||
checkNotNullable,
|
||||
Since,
|
||||
valueOfNonNullableParamWithDefault,
|
||||
HttpStatus;
|
||||
import 'dart:async';
|
||||
import 'dart:collection'
|
||||
show
|
||||
|
|
|
@ -2678,6 +2678,30 @@ class _HttpClient implements HttpClient {
|
|||
}
|
||||
}
|
||||
|
||||
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<_HttpClientRequest> _openUrl(String method, Uri uri) {
|
||||
if (_closing) {
|
||||
throw StateError("Client is closed");
|
||||
|
@ -2686,9 +2710,11 @@ class _HttpClient implements HttpClient {
|
|||
// Ignore any fragments on the request URI.
|
||||
uri = uri.removeFragment();
|
||||
|
||||
if (method == null) {
|
||||
throw ArgumentError(method);
|
||||
// from https://www.rfc-editor.org/rfc/rfc2616#page-35
|
||||
if (!_isValidToken(method)) {
|
||||
throw ArgumentError.value(method, "method");
|
||||
}
|
||||
|
||||
if (method != "CONNECT") {
|
||||
if (uri.host.isEmpty) {
|
||||
throw ArgumentError("No host specified in URI $uri");
|
||||
|
|
|
@ -16,7 +16,11 @@ import "dart:typed_data";
|
|||
import "package:expect/expect.dart";
|
||||
|
||||
import "../../../sdk/lib/internal/internal.dart"
|
||||
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||
show
|
||||
checkNotNullable,
|
||||
Since,
|
||||
valueOfNonNullableParamWithDefault,
|
||||
HttpStatus;
|
||||
|
||||
part "../../../sdk/lib/_http/crypto.dart";
|
||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
||||
|
|
|
@ -16,7 +16,11 @@ import "dart:typed_data";
|
|||
import "package:expect/expect.dart";
|
||||
|
||||
import "../../../sdk/lib/internal/internal.dart"
|
||||
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||
show
|
||||
checkNotNullable,
|
||||
Since,
|
||||
valueOfNonNullableParamWithDefault,
|
||||
HttpStatus;
|
||||
|
||||
part "../../../sdk/lib/_http/crypto.dart";
|
||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
||||
|
|
28
tests/standalone/io/http_open_method_validate_test.dart
Normal file
28
tests/standalone/io/http_open_method_validate_test.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
//
|
||||
// Verify that HttpClient open, openUrl method argument is validated.
|
||||
|
||||
import "dart:io";
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void testInvalidArgumentException(String method) {
|
||||
Expect.throws(() => HttpClient()..open(method, "127.0.0.1", 8080, "/"),
|
||||
(e) => e is ArgumentError);
|
||||
Expect.throws(
|
||||
() => HttpClient()..openUrl(method, Uri.parse("http://127.0.0.1/")),
|
||||
(e) => e is ArgumentError);
|
||||
}
|
||||
|
||||
main() {
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -16,7 +16,11 @@ import "dart:typed_data";
|
|||
import "package:expect/expect.dart";
|
||||
|
||||
import "../../../sdk/lib/internal/internal.dart"
|
||||
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||
show
|
||||
checkNotNullable,
|
||||
Since,
|
||||
valueOfNonNullableParamWithDefault,
|
||||
HttpStatus;
|
||||
|
||||
part "../../../sdk/lib/_http/crypto.dart";
|
||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
||||
|
|
|
@ -17,7 +17,11 @@ import "package:async_helper/async_helper.dart";
|
|||
import "package:expect/expect.dart";
|
||||
|
||||
import "../../../sdk/lib/internal/internal.dart"
|
||||
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
|
||||
show
|
||||
checkNotNullable,
|
||||
Since,
|
||||
valueOfNonNullableParamWithDefault,
|
||||
HttpStatus;
|
||||
|
||||
part "../../../sdk/lib/_http/crypto.dart";
|
||||
part "../../../sdk/lib/_http/embedder_config.dart";
|
||||
|
|
30
tests/standalone_2/io/http_open_method_validate_test.dart
Normal file
30
tests/standalone_2/io/http_open_method_validate_test.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
//
|
||||
// Verify that HttpClient open, openUrl method argument is validated.
|
||||
|
||||
// @dart = 2.9
|
||||
|
||||
import "dart:io";
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void testInvalidArgumentException(String method) {
|
||||
Expect.throws(() => HttpClient()..open(method, "127.0.0.1", 8080, "/"),
|
||||
(e) => e is ArgumentError);
|
||||
Expect.throws(
|
||||
() => HttpClient()..openUrl(method, Uri.parse("http://127.0.0.1/")),
|
||||
(e) => e is ArgumentError);
|
||||
}
|
||||
|
||||
main() {
|
||||
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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue