Validate request methods against a regex (#512)

Fixes #511
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7edf67..e786f21 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
 ## 0.13.3-dev
 
+* Validate that the `method` parameter of BaseRequest is a valid "token".
+
 ## 0.13.2
 
 * Add `package:http/retry.dart` with `RetryClient`. This is the same
diff --git a/lib/src/base_request.dart b/lib/src/base_request.dart
index 6380cb0..fd18bad 100644
--- a/lib/src/base_request.dart
+++ b/lib/src/base_request.dart
@@ -88,8 +88,17 @@
   bool get finalized => _finalized;
   bool _finalized = false;
 
-  BaseRequest(this.method, this.url)
-      : headers = LinkedHashMap(
+  static final _tokenRE = RegExp(r"^[\w!#%&'*+\-.^`|~]+$");
+  static String _validateMethod(String method) {
+    if (!_tokenRE.hasMatch(method)) {
+      throw ArgumentError.value(method, 'method', 'Not a valid method');
+    }
+    return method;
+  }
+
+  BaseRequest(String method, this.url)
+      : method = _validateMethod(method),
+        headers = LinkedHashMap(
             equals: (key1, key2) => key1.toLowerCase() == key2.toLowerCase(),
             hashCode: (key) => key.toLowerCase().hashCode);
 
diff --git a/test/request_test.dart b/test/request_test.dart
index 5b74bff..59cb098 100644
--- a/test/request_test.dart
+++ b/test/request_test.dart
@@ -334,4 +334,10 @@
       expect(request.toString(), 'POST $dummyUrl');
     });
   });
+
+  group('#method', () {
+    test('must be a token', () {
+      expect(() => http.Request('LLAMA[0]', dummyUrl), throwsArgumentError);
+    });
+  });
 }
diff --git a/test/streamed_request_test.dart b/test/streamed_request_test.dart
index c8c801d..4baa3e6 100644
--- a/test/streamed_request_test.dart
+++ b/test/streamed_request_test.dart
@@ -24,4 +24,10 @@
       expect(() => request.contentLength = 10, throwsStateError);
     });
   });
+  group('#method', () {
+    test('must be a token', () {
+      expect(() => http.StreamedRequest('SUPER LLAMA', dummyUrl),
+          throwsArgumentError);
+    });
+  });
 }