Return the correct HTTP status code for badly formatted requests. (#112)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 077573c..a8e723c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.7.5
+
+* Return the correct HTTP status code for badly formatted requests.
+
 ## 0.7.4+1
 
 * Allow `stream_channel` version 2.x
diff --git a/lib/shelf_io.dart b/lib/shelf_io.dart
index 73c514b..94a1889 100644
--- a/lib/shelf_io.dart
+++ b/lib/shelf_io.dart
@@ -73,9 +73,23 @@
   Request shelfRequest;
   try {
     shelfRequest = _fromHttpRequest(request);
+  } on ArgumentError catch (error, stackTrace) {
+    if (error.name == 'method' || error.name == 'requestedUri') {
+      // TODO: use a reduced log level when using package:logging
+      _logTopLevelError('Error parsing request.\n$error', stackTrace);
+      final response = Response(400,
+          body: 'Bad Request',
+          headers: {HttpHeaders.contentTypeHeader: 'text/plain'});
+      await _writeResponse(response, request.response);
+    } else {
+      _logTopLevelError('Error parsing request.\n$error', stackTrace);
+      final response = Response.internalServerError();
+      await _writeResponse(response, request.response);
+    }
+    return;
   } catch (error, stackTrace) {
-    var response =
-        _logTopLevelError('Error parsing request.\n$error', stackTrace);
+    _logTopLevelError('Error parsing request.\n$error', stackTrace);
+    final response = Response.internalServerError();
     await _writeResponse(response, request.response);
     return;
   }
@@ -203,10 +217,11 @@
   buffer.writeln();
   buffer.write(message);
 
-  return _logTopLevelError(buffer.toString(), stackTrace);
+  _logTopLevelError(buffer.toString(), stackTrace);
+  return Response.internalServerError();
 }
 
-Response _logTopLevelError(String message, [StackTrace stackTrace]) {
+void _logTopLevelError(String message, [StackTrace stackTrace]) {
   var chain = Chain.current();
   if (stackTrace != null) {
     chain = Chain.forTrace(stackTrace);
@@ -218,5 +233,4 @@
   stderr.writeln('ERROR - ${DateTime.now()}');
   stderr.writeln(message);
   stderr.writeln(chain);
-  return Response.internalServerError();
 }
diff --git a/lib/src/request.dart b/lib/src/request.dart
index 4351737..5189be2 100644
--- a/lib/src/request.dart
+++ b/lib/src/request.dart
@@ -167,20 +167,24 @@
         this.handlerPath = _computeHandlerPath(requestedUri, handlerPath, url),
         this._onHijack = onHijack,
         super(body, encoding: encoding, headers: headers, context: context) {
-    if (method.isEmpty) throw ArgumentError('method cannot be empty.');
+    if (method.isEmpty)
+      throw ArgumentError.value(method, 'method', 'cannot be empty.');
 
     if (!requestedUri.isAbsolute) {
-      throw ArgumentError(
-          'requestedUri "$requestedUri" must be an absolute URL.');
+      throw ArgumentError.value(
+          requestedUri, 'requestedUri', 'must be an absolute URL.');
     }
 
     if (requestedUri.fragment.isNotEmpty) {
-      throw ArgumentError(
-          'requestedUri "$requestedUri" may not have a fragment.');
+      throw ArgumentError.value(
+          requestedUri, 'requestedUri', 'may not have a fragment.');
     }
 
     if (this.handlerPath + this.url.path != this.requestedUri.path) {
-      throw ArgumentError('handlerPath "$handlerPath" and url "$url" must '
+      throw ArgumentError.value(
+          requestedUri,
+          'requestedUri',
+          'handlerPath "$handlerPath" and url "$url" must '
           'combine to equal requestedUri path "${requestedUri.path}".');
     }
   }
diff --git a/pubspec.yaml b/pubspec.yaml
index 8219143..9cc7860 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: shelf
-version: 0.7.4+1
+version: 0.7.5-dev
 description: >-
   A model for web server middleware that encourages composition and easy reuse
 author: Dart Team <misc@dartlang.org>
diff --git a/test/shelf_io_test.dart b/test/shelf_io_test.dart
index 3e94561..c679cd0 100644
--- a/test/shelf_io_test.dart
+++ b/test/shelf_io_test.dart
@@ -267,7 +267,7 @@
     expect(response.body, 'Hello from /');
   });
 
-  test('a bad HTTP request results in a 500 response', () async {
+  test('a bad HTTP host request results in a 500 response', () async {
     await _scheduleServer(syncHandler);
 
     var socket = await Socket.connect('localhost', _serverPort);
@@ -284,6 +284,21 @@
         await utf8.decodeStream(socket), contains('500 Internal Server Error'));
   });
 
+  test('a bad HTTP URL request results in a 400 response', () async {
+    await _scheduleServer(syncHandler);
+    final socket = await Socket.connect('localhost', _serverPort);
+
+    try {
+      socket.write('GET /#/ HTTP/1.1\r\n');
+      socket.write('Host: localhost\r\n');
+      socket.write('\r\n');
+    } finally {
+      await socket.close();
+    }
+
+    expect(await utf8.decodeStream(socket), contains('400 Bad Request'));
+  });
+
   group('date header', () {
     test('is sent by default', () async {
       await _scheduleServer(syncHandler);