Add support for CONNECT to httpcli code and flesh out handshaker implementation.
diff --git a/src/core/ext/client_config/http_connect_handshaker.c b/src/core/ext/client_config/http_connect_handshaker.c
index 2b71ca6..c649796 100644
--- a/src/core/ext/client_config/http_connect_handshaker.c
+++ b/src/core/ext/client_config/http_connect_handshaker.c
@@ -36,6 +36,8 @@
 #include <grpc/impl/codegen/alloc.h>
 #include <grpc/impl/codegen/log.h>
 
+#include "src/core/lib/http/format_request.h"
+#include "src/core/lib/http/parser.h"
 #include "src/core/ext/client_config/http_connect_handshaker.h"
 
 typedef struct http_connect_handshaker {
@@ -53,35 +55,65 @@
   grpc_closure request_done_closure;
   grpc_slice_buffer response_buffer;
   grpc_closure response_read_closure;
+  grpc_http_parser http_parser;
+  grpc_http_response http_response;
 } http_connect_handshaker;
 
-// Callback invoked for reading HTTP CONNECT response.
-static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
-                         grpc_error* error) {
-  http_connect_handshaker* h = arg;
-// FIXME: process response; on failure, figure out how to abort
-
-  // Invoke handshake-done callback.
-  h->cb(exec_ctx, h->endpoint, h->args, h->user_data);
-}
-
 // Callback invoked when finished writing HTTP CONNECT request.
 static void on_write_done(grpc_exec_ctx* exec_ctx, void* arg,
                           grpc_error* error) {
   http_connect_handshaker* h = arg;
   // Read HTTP CONNECT response.
-  gpr_slice_buffer_init(&h->response_buffer);
-  grpc_closure_init(&h->response_read_closure, on_read_done, h);
   grpc_endpoint_read(exec_ctx, h->endpoint, &h->response_buffer,
                      &h->response_read_closure);
 }
 
+// Callback invoked for reading HTTP CONNECT response.
+static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
+                         grpc_error* error) {
+  http_connect_handshaker* h = arg;
+  if (error == GRPC_ERROR_NONE) {
+    for (size_t i = 0; i < h->response_buffer.count; ++i) {
+      if (GPR_SLICE_LENGTH(h->response_buffer.slices[i]) > 0) {
+        error = grpc_http_parser_parse(
+            &h->http_parser, h->response_buffer.slices[i]);
+        if (error != GRPC_ERROR_NONE)
+          goto done;
+      }
+    }
+    // If we're not done reading the response, read more data.
+    // TODO(roth): In practice, I suspect that the response to a CONNECT
+    // request will never include a body, in which case this check is
+    // sufficient.  However, the language of RFC-2817 doesn't explicitly
+    // forbid the response from including a body.  If there is a body,
+    // it's possible that we might have parsed part but not all of the
+    // body, in which case this check will cause us to fail to parse the
+    // remainder of the body.  If that ever becomes an issue, we may
+    // need to fix the HTTP parser to understand when the body is
+    // complete (e.g., handling chunked transfer encoding or looking
+    // at the Content-Length: header).
+    if (h->http_parser->state != GRPC_HTTP_BODY) {
+      grpc_endpoint_read(exec_ctx, h->endpoint, &h->response_buffer,
+                         &h->response_read_closure);
+      return;
+    }
+  }
+ done:
+  // Invoke handshake-done callback.
+// FIXME: pass error to callback
+  h->cb(exec_ctx, h->endpoint, h->args, h->user_data);
+}
+
 //
 // Public handshaker methods
 //
 
 static void http_connect_handshaker_destroy(grpc_exec_ctx* exec_ctx,
                                             grpc_handshaker* handshaker) {
+  grpc_slice_buffer_destroy(&handshaker->request_buffer);
+  grpc_slice_buffer_destroy(&handshaker->response_buffer);
+  grpc_http_parser_destroy(&handshaker->http_parser);
+  grpc_http_response_destroy(&handshaker->http_response);
   gpr_free(handshaker);
 }
 
@@ -100,14 +132,24 @@
   h->args = args;
   h->cb = cb;
   h->user_data = user_data;
-  // Send HTTP CONNECT request.
+  // Initialize fields.
   gpr_slice_buffer_init(&h->request_buffer);
-  gpr_slice_buffer_add(&h->request_buffer, "HTTP CONNECT ");
-// FIXME: get server name from somewhere...
-  gpr_slice_buffer_add(&h->request_buffer, WHEE);
-// FIXME: add headers as needed?
-  gpr_slice_buffer_add(&h->request_buffer, "\n\n");
   grpc_closure_init(&h->request_done_closure, on_write_done, h);
+  gpr_slice_buffer_init(&h->response_buffer);
+  grpc_closure_init(&h->response_read_closure, on_read_done, h);
+  grpc_http_parser_init(&h->http_parser, GRPC_HTTP_RESPONSE,
+                        &h->http_response);
+  // Send HTTP CONNECT request.
+  grpc_httpcli_request request;
+  memset(&request, 0, sizeof(request));
+  // FIXME: get proxy name from somewhere...
+  request.host = gpr_strdup("");
+  request.http.method = gpr_strdup("CONNECT");
+  // FIXME: get server name from somewhere...
+  request.http.path = gpr_strdup("");
+  request.handshaker = grpc_httpcli_plaintext;
+  gpr_slice request_slice = grpc_httpcli_format_connect_request(request);
+  gpr_slice_buffer_add(&h->request_buffer, request_slice);
   grpc_endpoint_write(exec_ctx, endpoint, &h->request_buffer,
                       &h->request_done_closure);
 }