Use http_parser's AuthenticationChallenge class.
R=rnystrom@google.com
Review URL: https://codereview.chromium.org//1304363005 .
diff --git a/lib/src/client.dart b/lib/src/client.dart
index d604696..adf53d5 100644
--- a/lib/src/client.dart
+++ b/lib/src/client.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'package:http/http.dart' as http;
+import 'package:http_parser/http_parser.dart';
import 'authorization_exception.dart';
import 'credentials.dart';
@@ -83,7 +84,7 @@
/// [httpClient] is the underlying client that this forwards requests to after
/// adding authorization credentials to them.
///
- /// Thrwos an [ArgumentError] if [secret] is passed without [identifier].
+ /// Throws an [ArgumentError] if [secret] is passed without [identifier].
Client(this._credentials, {this.identifier, this.secret,
bool basicAuth: true, http.Client httpClient})
: _basicAuth = basicAuth,
@@ -109,17 +110,19 @@
if (response.statusCode != 401) return response;
if (!response.headers.containsKey('www-authenticate')) return response;
- var authenticate;
+ var challenges;
try {
- authenticate = new AuthenticateHeader.parse(
+ challenges = AuthenticationChallenge.parseHeader(
response.headers['www-authenticate']);
} on FormatException catch (_) {
return response;
}
- if (authenticate.scheme != 'bearer') return response;
+ var challenge = challenges.firstWhere(
+ (challenge) => challenge.scheme == 'bearer', orElse: () => null);
+ if (challenge == null) return response;
- var params = authenticate.parameters;
+ var params = challenge.parameters;
if (!params.containsKey('error')) return response;
throw new AuthorizationException(
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index af19f90..bf260eb 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -17,61 +17,3 @@
var userPass = Uri.encodeFull(identifier) + ":" + Uri.encodeFull(secret);
return "Basic " + CryptoUtils.bytesToBase64(ASCII.encode(userPass));
}
-
-/// Like [String.split], but only splits on the first occurrence of the pattern.
-///
-/// This will always return a list of two elements or fewer.
-List<String> split1(String toSplit, String pattern) {
- if (toSplit.isEmpty) return [];
-
- var index = toSplit.indexOf(pattern);
- if (index == -1) return [toSplit];
- return [toSplit.substring(0, index),
- toSplit.substring(index + pattern.length)];
-}
-
-/// A WWW-Authenticate header value, parsed as per [RFC 2617][].
-///
-/// [RFC 2617]: http://tools.ietf.org/html/rfc2617
-class AuthenticateHeader {
- final String scheme;
- final Map<String, String> parameters;
-
- AuthenticateHeader(this.scheme, this.parameters);
-
- /// Parses a header string. Throws a [FormatException] if the header is
- /// invalid.
- factory AuthenticateHeader.parse(String header) {
- var split = split1(header, ' ');
- if (split.length == 0) {
- throw new FormatException('Invalid WWW-Authenticate header: "$header"');
- } else if (split.length == 1 || split[1].trim().isEmpty) {
- return new AuthenticateHeader(split[0].toLowerCase(), {});
- }
- var scheme = split[0].toLowerCase();
- var paramString = split[1];
-
- // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html.
- var tokenChar = r'[^\0-\x1F()<>@,;:\\"/\[\]?={} \t\x7F]';
- var quotedStringChar = r'(?:[^\0-\x1F\x7F"]|\\.)';
- var regexp = new RegExp('^ *($tokenChar+)="($quotedStringChar*)" *(, *)?');
-
- var parameters = {};
- var match;
- do {
- match = regexp.firstMatch(paramString);
- if (match == null) {
- throw new FormatException('Invalid WWW-Authenticate header: "$header"');
- }
-
- paramString = paramString.substring(match.end);
- parameters[match.group(1).toLowerCase()] = match.group(2);
- } while (match.group(3) != null);
-
- if (!paramString.trim().isEmpty) {
- throw new FormatException('Invalid WWW-Authenticate header: "$header"');
- }
-
- return new AuthenticateHeader(scheme, parameters);
- }
-}
diff --git a/pubspec.yaml b/pubspec.yaml
index ce4bd4a..f52b8be 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -10,6 +10,6 @@
sdk: '>=1.9.0 <2.0.0'
dependencies:
http: '>=0.11.0 <0.12.0'
- http_parser: '>=0.0.0 <2.0.0'
+ http_parser: '^1.0.0'
dev_dependencies:
test: '>=0.12.0 <0.13.0'
diff --git a/test/client_test.dart b/test/client_test.dart
index 885f83e..7dc5afd 100644
--- a/test/client_test.dart
+++ b/test/client_test.dart
@@ -178,8 +178,8 @@
expect(request.headers['authorization'],
equals('Bearer access token'));
- var authenticate = 'Bearer error="invalid_token", error_description='
- '"Something is terribly wrong.", ';
+ var authenticate = 'Bearer error="invalid_token" error_description='
+ '"Something is terribly wrong."';
return new Future.value(new http.Response('bad job', 401,
headers: {'www-authenticate': authenticate}));
});
diff --git a/test/utils_test.dart b/test/utils_test.dart
deleted file mode 100644
index 54c2da5..0000000
--- a/test/utils_test.dart
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2012, 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.
-
-import 'package:oauth2/src/utils.dart';
-import 'package:test/test.dart';
-
-void main() {
- group('AuthenticateHeader', () {
- test("parses a scheme", () {
- var header = new AuthenticateHeader.parse('bearer');
- expect(header.scheme, equals('bearer'));
- expect(header.parameters, equals({}));
- });
-
- test("lower-cases the scheme", () {
- var header = new AuthenticateHeader.parse('BeaRer');
- expect(header.scheme, equals('bearer'));
- expect(header.parameters, equals({}));
- });
-
- test("parses a scheme with trailing whitespace", () {
- var header = new AuthenticateHeader.parse('bearer ');
- expect(header.scheme, equals('bearer'));
- expect(header.parameters, equals({}));
- });
-
- test("parses a scheme with one param", () {
- var header = new AuthenticateHeader.parse('bearer foo="bar"');
- expect(header.scheme, equals('bearer'));
- expect(header.parameters, equals({'foo': 'bar'}));
- });
-
- test("parses a scheme with several params", () {
- var header = new AuthenticateHeader.parse(
- 'bearer foo="bar", bar="baz" ,baz="qux"');
- expect(header.scheme, equals('bearer'));
- expect(header.parameters, equals({
- 'foo': 'bar',
- 'bar': 'baz',
- 'baz': 'qux'
- }));
- });
-
- test("lower-cases parameter names but not values", () {
- var header = new AuthenticateHeader.parse('bearer FoO="bAr"');
- expect(header.scheme, equals('bearer'));
- expect(header.parameters, equals({'foo': 'bAr'}));
- });
-
- test("allows empty values", () {
- var header = new AuthenticateHeader.parse('bearer foo=""');
- expect(header.scheme, equals('bearer'));
- expect(header.parameters, equals({'foo': ''}));
- });
-
- test("won't parse an empty string", () {
- expect(() => new AuthenticateHeader.parse(''),
- throwsFormatException);
- });
-
- test("won't parse a token without a value", () {
- expect(() => new AuthenticateHeader.parse('bearer foo'),
- throwsFormatException);
-
- expect(() => new AuthenticateHeader.parse('bearer foo='),
- throwsFormatException);
- });
-
- test("won't parse a token without a value", () {
- expect(() => new AuthenticateHeader.parse('bearer foo'),
- throwsFormatException);
-
- expect(() => new AuthenticateHeader.parse('bearer foo='),
- throwsFormatException);
- });
-
- test("won't parse a trailing comma", () {
- expect(() => new AuthenticateHeader.parse('bearer foo="bar",'),
- throwsFormatException);
- });
-
- test("won't parse a multiple params without a comma", () {
- expect(() => new AuthenticateHeader.parse('bearer foo="bar" bar="baz"'),
- throwsFormatException);
- });
- });
-}