Add support for controlling HttpResponse.bufferOutput to shelf_io.

Closes #7

R=kevmoo@google.com

Review URL: https://codereview.chromium.org//1037483002
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24d9ba1..e66a474 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,9 @@
 ## 0.6.1
 
-** Fixed spelling errors in README and code comments.
+* `shelf_io` now takes a `"shelf.io.buffer_output"` `Response.context` parameter
+  that controls `HttpResponse.bufferOutput`.
+
+* Fixed spelling errors in README and code comments.
 
 ## 0.6.0
 
diff --git a/lib/shelf_io.dart b/lib/shelf_io.dart
index 4ca48b6..301050f 100644
--- a/lib/shelf_io.dart
+++ b/lib/shelf_io.dart
@@ -7,7 +7,14 @@
 /// One can provide an instance of [HttpServer] as the `requests` parameter in
 /// [serveRequests].
 ///
-/// The `dart:io` adapter supports request hijacking; see [Request.hijack].
+/// This adapter supports request hijacking; see [Request.hijack]. It also
+/// supports the `"shelf.io.buffer_output"` `Response.context` property. If this
+/// property is `true` (the default), streamed responses will be buffered to
+/// improve performance; if it's `false`, all chunks will be pushed over the
+/// wire as they're received. See [`HttpResponse.bufferOutput`][bufferOutput]
+/// for more information.
+///
+/// [bufferOutput]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:io.HttpResponse#id_bufferOutput
 library shelf.io;
 
 import 'dart:async';
@@ -78,17 +85,17 @@
   }).then((response) {
     if (response == null) {
       response = _logError('null response from handler.');
-    } else if (!shelfRequest.canHijack) {
-      var message = new StringBuffer()
-        ..writeln("Got a response for hijacked request "
-            "${shelfRequest.method} ${shelfRequest.requestedUri}:")
-        ..writeln(response.statusCode);
-      response.headers
-          .forEach((key, value) => message.writeln("${key}: ${value}"));
-      throw new Exception(message.toString().trim());
+    } else if (shelfRequest.canHijack) {
+      return _writeResponse(response, request.response);
     }
 
-    return _writeResponse(response, request.response);
+    var message = new StringBuffer()
+      ..writeln("Got a response for hijacked request "
+          "${shelfRequest.method} ${shelfRequest.requestedUri}:")
+      ..writeln(response.statusCode);
+    response.headers
+        .forEach((key, value) => message.writeln("${key}: ${value}"));
+    throw new Exception(message.toString().trim());
   }).catchError((error, stackTrace) {
     // Ignore HijackExceptions.
     if (error is! HijackException) throw error;
@@ -118,6 +125,10 @@
 }
 
 Future _writeResponse(Response response, HttpResponse httpResponse) {
+  if (response.context.containsKey("shelf.io.buffer_output")) {
+    httpResponse.bufferOutput = response.context["shelf.io.buffer_output"];
+  }
+
   httpResponse.statusCode = response.statusCode;
 
   response.headers.forEach((header, value) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 5d0e402..0a94fe4 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: shelf
-version: 0.6.1-dev
+version: 0.6.1
 author: Dart Team <misc@dartlang.org>
 description: Web Server Middleware for Dart
 homepage: https://github.com/dart-lang/shelf
diff --git a/test/shelf_io_test.dart b/test/shelf_io_test.dart
index 586a961..11c5b7c 100644
--- a/test/shelf_io_test.dart
+++ b/test/shelf_io_test.dart
@@ -10,6 +10,7 @@
 
 import 'package:http/http.dart' as http;
 import 'package:http_parser/http_parser.dart' as parser;
+import 'package:scheduled_test/scheduled_stream.dart';
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:shelf/shelf.dart';
 import 'package:shelf/shelf_io.dart' as shelf_io;
@@ -331,6 +332,35 @@
       });
     });
   });
+
+  test('respects the "shelf.io.buffer_output" context parameter', () {
+    var controller = new StreamController();
+    _scheduleServer((request) {
+      controller.add("Hello, ");
+
+      return new Response.ok(UTF8.encoder.bind(controller.stream),
+          context: {"shelf.io.buffer_output": false});
+    });
+
+    schedule(() {
+      var request = new http.Request(
+          "GET", Uri.parse('http://localhost:$_serverPort/'));
+
+      return request.send().then((response) {
+        var stream = new ScheduledStream(UTF8.decoder.bind(response.stream));
+
+        return stream.next().then((data) {
+          expect(data, equals("Hello, "));
+          controller.add("world!");
+          return stream.next();
+        }).then((data) {
+          expect(data, equals("world!"));
+          controller.close();
+          expect(stream.hasNext, completion(isFalse));
+        });
+      });
+    });
+  });
 }
 
 int _serverPort;