From f7250197a733141be58bab3453b0ac1a2d278e62 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 22 Jul 2016 08:06:09 -0700 Subject: Add support for CONNECT to httpcli code and flesh out handshaker implementation. --- .../ext/client_config/http_connect_handshaker.c | 78 +++++++++++++++++----- 1 file changed, 60 insertions(+), 18 deletions(-) (limited to 'src/core/ext/client_config/http_connect_handshaker.c') 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 #include +#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); } -- cgit v1.2.3