aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/ext/client_config/http_connect_handshaker.c
diff options
context:
space:
mode:
authorGravatar Mark D. Roth <roth@google.com>2016-07-22 08:06:09 -0700
committerGravatar Mark D. Roth <roth@google.com>2016-07-22 08:06:09 -0700
commitf7250197a733141be58bab3453b0ac1a2d278e62 (patch)
tree773b469b5cad48fc5f8270e906837a620d354e5e /src/core/ext/client_config/http_connect_handshaker.c
parent9136bb1c1c8eb10f3ab7b26b0b947c1889d42ea6 (diff)
Add support for CONNECT to httpcli code and flesh out handshaker implementation.
Diffstat (limited to 'src/core/ext/client_config/http_connect_handshaker.c')
-rw-r--r--src/core/ext/client_config/http_connect_handshaker.c78
1 files changed, 60 insertions, 18 deletions
diff --git a/src/core/ext/client_config/http_connect_handshaker.c b/src/core/ext/client_config/http_connect_handshaker.c
index 2b71ca60f6..c649796f42 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 @@ typedef struct http_connect_handshaker {
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 @@ static void http_connect_handshaker_do_handshake(
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);
}