aboutsummaryrefslogtreecommitdiffhomepage
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
parent9136bb1c1c8eb10f3ab7b26b0b947c1889d42ea6 (diff)
Add support for CONNECT to httpcli code and flesh out handshaker implementation.
-rw-r--r--src/core/ext/client_config/http_connect_handshaker.c78
-rw-r--r--src/core/lib/http/format_request.c22
-rw-r--r--src/core/lib/http/format_request.h2
-rw-r--r--src/core/lib/http/httpcli.h6
-rw-r--r--src/core/lib/http/parser.c8
5 files changed, 85 insertions, 31 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);
}
diff --git a/src/core/lib/http/format_request.c b/src/core/lib/http/format_request.c
index 9240356fea..e818b70113 100644
--- a/src/core/lib/http/format_request.c
+++ b/src/core/lib/http/format_request.c
@@ -44,7 +44,7 @@
#include "src/core/lib/support/string.h"
static void fill_common_header(const grpc_httpcli_request *request,
- gpr_strvec *buf) {
+ gpr_strvec *buf, bool connection_close) {
size_t i;
gpr_strvec_add(buf, gpr_strdup(request->http.path));
gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n"));
@@ -52,7 +52,8 @@ static void fill_common_header(const grpc_httpcli_request *request,
gpr_strvec_add(buf, gpr_strdup("Host: "));
gpr_strvec_add(buf, gpr_strdup(request->host));
gpr_strvec_add(buf, gpr_strdup("\r\n"));
- gpr_strvec_add(buf, gpr_strdup("Connection: close\r\n"));
+ if (connection_close)
+ gpr_strvec_add(buf, gpr_strdup("Connection: close\r\n"));
gpr_strvec_add(buf,
gpr_strdup("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n"));
/* user supplied headers */
@@ -71,7 +72,7 @@ gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) {
gpr_strvec_init(&out);
gpr_strvec_add(&out, gpr_strdup("GET "));
- fill_common_header(request, &out);
+ fill_common_header(request, &out, true);
gpr_strvec_add(&out, gpr_strdup("\r\n"));
flat = gpr_strvec_flatten(&out, &flat_len);
@@ -91,7 +92,7 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
gpr_strvec_init(&out);
gpr_strvec_add(&out, gpr_strdup("POST "));
- fill_common_header(request, &out);
+ fill_common_header(request, &out, true);
if (body_bytes) {
uint8_t has_content_type = 0;
for (i = 0; i < request->http.hdr_count; i++) {
@@ -118,3 +119,16 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
return gpr_slice_new(tmp, out_len, gpr_free);
}
+
+gpr_slice grpc_httpcli_format_connect_request(
+ const grpc_httpcli_request *request) {
+ gpr_strvec out;
+ gpr_strvec_init(&out);
+ gpr_strvec_add(&out, gpr_strdup("CONNECT "));
+ fill_common_header(request, &out, false);
+ gpr_strvec_add(&out, gpr_strdup("\r\n"));
+ size_t flat_len;
+ char *flat = gpr_strvec_flatten(&out, &flat_len);
+ gpr_strvec_destroy(&out);
+ return gpr_slice_new(flat, flat_len, gpr_free);
+}
diff --git a/src/core/lib/http/format_request.h b/src/core/lib/http/format_request.h
index 1543efe4b0..7abd55f2f7 100644
--- a/src/core/lib/http/format_request.h
+++ b/src/core/lib/http/format_request.h
@@ -41,5 +41,7 @@ gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request);
gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
const char *body_bytes,
size_t body_size);
+gpr_slice grpc_httpcli_format_connect_request(
+ const grpc_httpcli_request *request);
#endif /* GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H */
diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h
index 662e176f4c..320c0f86c6 100644
--- a/src/core/lib/http/httpcli.h
+++ b/src/core/lib/http/httpcli.h
@@ -93,8 +93,7 @@ void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
'request' contains request parameters - these are caller owned and can be
destroyed once the call returns
'deadline' contains a deadline for the request (or gpr_inf_future)
- 'on_response' is a callback to report results to (and 'user_data' is a user
- supplied pointer to pass to said call) */
+ 'on_response' is a callback to report results to */
void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
const grpc_httpcli_request *request,
@@ -113,8 +112,7 @@ void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
'deadline' contains a deadline for the request (or gpr_inf_future)
'em' points to a caller owned event manager that must be alive for the
lifetime of the request
- 'on_response' is a callback to report results to (and 'user_data' is a user
- supplied pointer to pass to said call)
+ 'on_response' is a callback to report results to
Does not support ?var1=val1&var2=val2 in the path. */
void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
diff --git a/src/core/lib/http/parser.c b/src/core/lib/http/parser.c
index 92ed08ae51..d3bac5b876 100644
--- a/src/core/lib/http/parser.c
+++ b/src/core/lib/http/parser.c
@@ -282,20 +282,18 @@ static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte) {
if (grpc_http1_trace)
gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded",
GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
- return 0;
+ return GRPC_ERROR_NONE;
}
parser->cur_line[parser->cur_line_length] = byte;
parser->cur_line_length++;
if (check_line(parser)) {
return finish_line(parser);
- } else {
- return GRPC_ERROR_NONE;
}
- GPR_UNREACHABLE_CODE(return 0);
+ return GRPC_ERROR_NONE;
case GRPC_HTTP_BODY:
return addbyte_body(parser, byte);
}
- GPR_UNREACHABLE_CODE(return 0);
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_NONE);
}
void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,