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);
-    });
-  });
-}