Get curl uploads working on Mac.

Review URL: https://codereview.chromium.org//11411273

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@15592 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/utils/pub/curl_client.dart b/utils/pub/curl_client.dart
index 71b4701..e1afc2d 100644
--- a/utils/pub/curl_client.dart
+++ b/utils/pub/curl_client.dart
@@ -105,12 +105,17 @@
   /// receiving the response headers. [expectBody] indicates that the server is
   /// expected to send a response body (which is not the case for HEAD
   /// requests).
+  ///
+  /// Curl prints the headers to a file and then prints the body to stdout. So,
+  /// in theory, we could read the headers as soon as we see anything appear
+  /// in stdout. However, that seems to be too early to successfully read the
+  /// file (at least on Mac). Instead, this just waits until the entire process
+  /// has completed.
   Future _waitForHeaders(Process process, {bool expectBody}) {
-    var exitCompleter = new Completer<int>();
-    var exitFuture = exitCompleter.future;
+    var completer = new Completer();
     process.onExit = (exitCode) {
       if (exitCode == 0) {
-        exitCompleter.complete(0);
+        completer.complete(null);
         return;
       }
 
@@ -122,7 +127,7 @@
         } else {
           throw new HttpException(message);
         }
-      }), exitCompleter);
+      }), completer);
     };
 
     // If there's not going to be a response body (e.g. for HEAD requests), curl
@@ -131,40 +136,10 @@
     if (!expectBody) {
       return Futures.wait([
         consumeInputStream(process.stdout),
-        exitFuture
+        completer.future
       ]);
     }
 
-    // TODO(nweiz): remove this when issue 4061 is fixed.
-    var stackTrace;
-    try {
-      throw "";
-    } catch (_, localStackTrace) {
-      stackTrace = localStackTrace;
-    }
-
-    var completer = new Completer();
-    resetCallbacks() {
-      process.stdout.onData = null;
-      process.stdout.onError = null;
-      process.stdout.onClosed = null;
-    }
-    process.stdout.onData = () {
-      // TODO(nweiz): If an error happens after the body data starts being
-      // received, it should be piped through Response.stream once issue
-      // 3657 is fixed.
-      exitFuture.handleException((e) => true);
-      resetCallbacks();
-      completer.complete(null);
-    };
-    process.stdout.onError = (e) {
-      resetCallbacks();
-      completer.completeException(e, stackTrace);
-    };
-    process.stdout.onClosed = () {
-      resetCallbacks();
-      chainToCompleter(exitFuture, completer);
-    };
     return completer.future;
   }
 
diff --git a/utils/tests/pub/pub_lish_test.dart b/utils/tests/pub/pub_lish_test.dart
index 1b7c633..aa67161 100644
--- a/utils/tests/pub/pub_lish_test.dart
+++ b/utils/tests/pub/pub_lish_test.dart
@@ -204,11 +204,18 @@
     handleUploadForm(server);
 
     server.handle('POST', '/upload', (request, response) {
-      response.statusCode = 400;
-      response.headers.contentType = new ContentType('application', 'xml');
-      response.outputStream.writeString('<Error><Message>Your request sucked.'
-          '</Message></Error>');
-      return closeHttpResponse(request, response);
+      // TODO(rnystrom): HTTP requires that you don't start sending a response
+      // until the request has been completely sent, but dart:io doesn't
+      // ensure that (#7044). Workaround it by manually consuming the entire
+      // input stream before we start responding. If we don't do this, curl
+      // will choke on this on Mac and Windows.
+      return consumeInputStream(request.inputStream).transform((_) {
+        response.statusCode = 400;
+        response.headers.contentType = new ContentType('application', 'xml');
+        response.outputStream.writeString('<Error><Message>Your request sucked.'
+        '</Message></Error>');
+        response.outputStream.close();
+      });
     });
 
     // TODO(nweiz): This should use the server's error message once the client