Version 1.11.2

Cherry-pick 735e5a3eb4a5028eac3399679b3dcd51360d97c6 to stable
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9e2340d..cfe595a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 1.11.2
+
+### Core library changes
+
+* Fix a bug where `WebSocket.close()` would crash if called after
+  `WebSocket.cancel()`.
+
 ## 1.11.1
 
 ### Tool changes
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 2657606..9693873 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -903,6 +903,10 @@
     _subscription.pause();
     _controller = new StreamController(sync: true,
                                        onListen: _subscription.resume,
+                                       onCancel: () {
+                                         _subscription.cancel();
+                                         _subscription = null;
+                                       },
                                        onPause: _subscription.pause,
                                        onResume: _subscription.resume);
 
@@ -965,7 +969,7 @@
       //      processed if received.
       //   2) set a timer terminate the connection if a close frame is
       //      not received.
-      if (!_controller.hasListener) {
+      if (!_controller.hasListener && _subscription != null) {
         _controller.stream.drain().catchError((_) => {});
       }
       if (_closeTimer == null) {
@@ -974,7 +978,7 @@
           // Reuse code and reason from the local close.
           _closeCode = _outCloseCode;
           _closeReason = _outCloseReason;
-          _subscription.cancel();
+          if (_subscription != null) _subscription.cancel();
           _controller.close();
           _webSockets.remove(_serviceId);
         });
diff --git a/tests/standalone/io/web_socket_test.dart b/tests/standalone/io/web_socket_test.dart
index f3213e6..9ae1758 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -187,6 +187,36 @@
   }
 
 
+  void testCancelThenClose() {
+    createServer().then((server) {
+      server.transform(new WebSocketTransformer()).listen((webSocket) {
+        webSocket.listen(null).cancel();
+        webSocket.close();
+        server.close();
+      });
+
+      createClient(server.port).then((webSocket) {
+        webSocket.close();
+      });
+    });
+  }
+
+  void testCloseThenCancel() {
+    createServer().then((server) {
+      server.transform(new WebSocketTransformer()).listen((webSocket) {
+        var subscription = webSocket.listen(null);
+        webSocket.close();
+        subscription.cancel();
+        server.close();
+      });
+
+      createClient(server.port).then((webSocket) {
+        webSocket.close();
+      });
+    });
+  }
+
+
   void testListenAfterClose() {
     createServer().then((server) {
       server.transform(new WebSocketTransformer()).listen((webSocket) {
@@ -543,6 +573,8 @@
     testMessageLength(65535);
     testMessageLength(65536);
     testCloseNoListen();
+    testCancelThenClose();
+    testCloseThenCancel();
     testListenAfterClose();
     testDoubleCloseClient();
     testDoubleCloseServer();
diff --git a/tools/VERSION b/tools/VERSION
index 098b2ed..8a1172e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -26,6 +26,6 @@
 CHANNEL stable
 MAJOR 1
 MINOR 11
-PATCH 1
+PATCH 2
 PRERELEASE 0
 PRERELEASE_PATCH 0