Skip to content

Commit 45abfe1

Browse files
authored
Merge pull request #10 from markdroth/http_proxy_patch
Provide a cleaner API for proxy_connection_failed().
2 parents 906adfd + 1af674a commit 45abfe1

File tree

1 file changed

+70
-68
lines changed

1 file changed

+70
-68
lines changed

test/core/end2end/fixtures/http_proxy_fixture.cc

Lines changed: 70 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,6 @@ struct grpc_end2end_http_proxy {
6868
// Connection handling
6969
//
7070

71-
#define SERVER_EP_READ_FAIL 1
72-
#define SERVER_EP_WRITE_FAIL 2
73-
#define CLIENT_EP_READ_FAIL 4
74-
#define CLIENT_EP_WRITE_FAIL 8
75-
76-
#define SERVER_EP_FAIL (SERVER_EP_READ_FAIL | SERVER_EP_WRITE_FAIL)
77-
#define CLIENT_EP_FAIL (CLIENT_EP_READ_FAIL | CLIENT_EP_WRITE_FAIL)
78-
#define EP_FAIL (SERVER_EP_FAIL | CLIENT_EP_FAIL)
79-
8071
// proxy_connection structure is only accessed in the closures which are all
8172
// scheduled under the same combiner lock. So there is is no need for a mutex to
8273
// protect this structure.
@@ -88,13 +79,6 @@ typedef struct proxy_connection {
8879

8980
gpr_refcount refcount;
9081

91-
// The lower four bits store the endpoint failure information
92-
// bit-0 Server endpoint read failure
93-
// bit-1 Server endpoint write failure
94-
// bit-2 Client endpoint read failure
95-
// bit-3 Client endpoint write failure
96-
int ep_state;
97-
9882
grpc_pollset_set* pollset_set;
9983

10084
// NOTE: All the closures execute under proxy->combiner lock. Which means
@@ -107,6 +91,13 @@ typedef struct proxy_connection {
10791
grpc_closure on_server_read_done;
10892
grpc_closure on_server_write_done;
10993

94+
bool client_read_failed : 1;
95+
bool client_write_failed : 1;
96+
bool client_shutdown : 1;
97+
bool server_read_failed : 1;
98+
bool server_write_failed : 1;
99+
bool server_shutdown : 1;
100+
110101
grpc_slice_buffer client_read_buffer;
111102
grpc_slice_buffer client_deferred_write_buffer;
112103
bool client_is_writing;
@@ -150,36 +141,52 @@ static void proxy_connection_unref(grpc_exec_ctx* exec_ctx,
150141
}
151142
}
152143

144+
enum failure_type {
145+
SETUP_FAILED, // To be used before we start proxying.
146+
CLIENT_READ_FAILED,
147+
CLIENT_WRITE_FAILED,
148+
SERVER_READ_FAILED,
149+
SERVER_WRITE_FAILED,
150+
};
151+
153152
// Helper function to shut down the proxy connection.
154-
// Does NOT take ownership of a reference to error.
155153
static void proxy_connection_failed(grpc_exec_ctx* exec_ctx,
156-
proxy_connection* conn, int failure_type,
157-
const char* prefix, grpc_error* error) {
158-
const char* msg = grpc_error_string(error);
159-
gpr_log(GPR_INFO, "%s: %s", prefix, msg);
160-
int ep_state = conn->ep_state;
161-
int new_ep_state = ep_state | failure_type;
162-
if (ep_state != new_ep_state) {
163-
conn->ep_state = new_ep_state;
164-
// Shutdown the endpoint (client and/or server) if both read and write
165-
// failures are observed after setting the failure_type.
166-
// To prevent calling endpoint shutdown multiple times, It is important to
167-
// ensure that ep_state i.e the old state, did not already have both
168-
// failures set.
169-
if (((ep_state & SERVER_EP_FAIL) != SERVER_EP_FAIL) &&
170-
((new_ep_state & SERVER_EP_FAIL) == SERVER_EP_FAIL)) {
171-
if (conn->server_endpoint != nullptr) {
172-
grpc_endpoint_shutdown(exec_ctx, conn->server_endpoint,
173-
GRPC_ERROR_REF(error));
174-
}
154+
proxy_connection* conn,
155+
failure_type failure, const char* prefix,
156+
grpc_error* error) {
157+
gpr_log(GPR_INFO, "%s: %s", prefix, grpc_error_string(error));
158+
// Decide whether we should shut down the client and server.
159+
bool shutdown_client = false;
160+
bool shutdown_server = false;
161+
if (failure == SETUP_FAILED) {
162+
shutdown_client = true;
163+
shutdown_server = true;
164+
} else {
165+
if ((failure == CLIENT_READ_FAILED && conn->client_write_failed) ||
166+
(failure == CLIENT_WRITE_FAILED && conn->client_read_failed) ||
167+
(failure == SERVER_READ_FAILED && !conn->client_is_writing)) {
168+
shutdown_client = true;
175169
}
176-
if (((ep_state & CLIENT_EP_FAIL) != CLIENT_EP_FAIL) &&
177-
((new_ep_state & CLIENT_EP_FAIL) == CLIENT_EP_FAIL)) {
178-
grpc_endpoint_shutdown(exec_ctx, conn->client_endpoint,
179-
GRPC_ERROR_REF(error));
170+
if ((failure == SERVER_READ_FAILED && conn->server_write_failed) ||
171+
(failure == SERVER_WRITE_FAILED && conn->server_read_failed) ||
172+
(failure == CLIENT_READ_FAILED && !conn->server_is_writing)) {
173+
shutdown_server = true;
180174
}
181175
}
176+
// If we decided to shut down either one and have not yet done so, do so.
177+
if (shutdown_client && !conn->client_shutdown) {
178+
grpc_endpoint_shutdown(exec_ctx, conn->client_endpoint,
179+
GRPC_ERROR_REF(error));
180+
conn->client_shutdown = true;
181+
}
182+
if (shutdown_server && !conn->server_shutdown) {
183+
grpc_endpoint_shutdown(exec_ctx, conn->server_endpoint,
184+
GRPC_ERROR_REF(error));
185+
conn->server_shutdown = true;
186+
}
187+
// Unref the connection.
182188
proxy_connection_unref(exec_ctx, conn, "conn_failed");
189+
GRPC_ERROR_UNREF(error);
183190
}
184191

185192
// Callback for writing proxy data to the client.
@@ -188,8 +195,8 @@ static void on_client_write_done(grpc_exec_ctx* exec_ctx, void* arg,
188195
proxy_connection* conn = (proxy_connection*)arg;
189196
conn->client_is_writing = false;
190197
if (error != GRPC_ERROR_NONE) {
191-
proxy_connection_failed(exec_ctx, conn, CLIENT_EP_WRITE_FAIL,
192-
"HTTP proxy client write", error);
198+
proxy_connection_failed(exec_ctx, conn, CLIENT_WRITE_FAILED,
199+
"HTTP proxy client write", GRPC_ERROR_REF(error));
193200
return;
194201
}
195202
// Clear write buffer (the data we just wrote).
@@ -215,8 +222,8 @@ static void on_server_write_done(grpc_exec_ctx* exec_ctx, void* arg,
215222
proxy_connection* conn = (proxy_connection*)arg;
216223
conn->server_is_writing = false;
217224
if (error != GRPC_ERROR_NONE) {
218-
proxy_connection_failed(exec_ctx, conn, SERVER_EP_WRITE_FAIL,
219-
"HTTP proxy server write", error);
225+
proxy_connection_failed(exec_ctx, conn, SERVER_WRITE_FAILED,
226+
"HTTP proxy server write", GRPC_ERROR_REF(error));
220227
return;
221228
}
222229
// Clear write buffer (the data we just wrote).
@@ -244,11 +251,8 @@ static void on_client_read_done(grpc_exec_ctx* exec_ctx, void* arg,
244251
if (error != GRPC_ERROR_NONE) {
245252
// Report a read failure on the client endpoint. If there is no pending
246253
// server write, then shutdown the server endpoint as well.
247-
proxy_connection_failed(
248-
exec_ctx, conn,
249-
(conn->server_is_writing ? CLIENT_EP_READ_FAIL
250-
: (CLIENT_EP_READ_FAIL | SERVER_EP_FAIL)),
251-
"HTTP proxy client read", error);
254+
proxy_connection_failed(exec_ctx, conn, CLIENT_READ_FAILED,
255+
"HTTP proxy client read", GRPC_ERROR_REF(error));
252256
return;
253257
}
254258
// If there is already a pending write (i.e., server_write_buffer is
@@ -282,11 +286,8 @@ static void on_server_read_done(grpc_exec_ctx* exec_ctx, void* arg,
282286
if (error != GRPC_ERROR_NONE) {
283287
// Report a read failure on the server end point. If there is no pending
284288
// write to the client, then shutdown the client endpoint as well.
285-
proxy_connection_failed(
286-
exec_ctx, conn,
287-
(conn->client_is_writing ? SERVER_EP_READ_FAIL
288-
: (SERVER_EP_READ_FAIL | CLIENT_EP_FAIL)),
289-
"HTTP proxy server read", error);
289+
proxy_connection_failed(exec_ctx, conn, SERVER_READ_FAILED,
290+
"HTTP proxy server read", GRPC_ERROR_REF(error));
290291
return;
291292
}
292293
// If there is already a pending write (i.e., client_write_buffer is
@@ -318,8 +319,8 @@ static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg,
318319
proxy_connection* conn = (proxy_connection*)arg;
319320
conn->client_is_writing = false;
320321
if (error != GRPC_ERROR_NONE) {
321-
proxy_connection_failed(exec_ctx, conn, EP_FAIL,
322-
"HTTP proxy write response", error);
322+
proxy_connection_failed(exec_ctx, conn, SETUP_FAILED,
323+
"HTTP proxy write response", GRPC_ERROR_REF(error));
323324
return;
324325
}
325326
// Clear write buffer.
@@ -347,8 +348,8 @@ static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg,
347348
// connection failed. However, for the purposes of this test code,
348349
// it's fine to pretend this is a client-side error, which will
349350
// cause the client connection to be dropped.
350-
proxy_connection_failed(exec_ctx, conn, EP_FAIL,
351-
"HTTP proxy server connect", error);
351+
proxy_connection_failed(exec_ctx, conn, SETUP_FAILED,
352+
"HTTP proxy server connect", GRPC_ERROR_REF(error));
352353
return;
353354
}
354355
// We've established a connection, so send back a 200 response code to
@@ -397,8 +398,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
397398
gpr_log(GPR_DEBUG, "on_read_request_done: %p %s", conn,
398399
grpc_error_string(error));
399400
if (error != GRPC_ERROR_NONE) {
400-
proxy_connection_failed(exec_ctx, conn, EP_FAIL, "HTTP proxy read request",
401-
error);
401+
proxy_connection_failed(exec_ctx, conn, SETUP_FAILED,
402+
"HTTP proxy read request", GRPC_ERROR_REF(error));
402403
return;
403404
}
404405
// Read request and feed it to the parser.
@@ -407,8 +408,9 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
407408
error = grpc_http_parser_parse(
408409
&conn->http_parser, conn->client_read_buffer.slices[i], nullptr);
409410
if (error != GRPC_ERROR_NONE) {
410-
proxy_connection_failed(exec_ctx, conn, EP_FAIL,
411-
"HTTP proxy request parse", error);
411+
proxy_connection_failed(exec_ctx, conn, SETUP_FAILED,
412+
"HTTP proxy request parse",
413+
GRPC_ERROR_REF(error));
412414
GRPC_ERROR_UNREF(error);
413415
return;
414416
}
@@ -428,8 +430,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
428430
conn->http_request.method);
429431
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
430432
gpr_free(msg);
431-
proxy_connection_failed(exec_ctx, conn, EP_FAIL, "HTTP proxy read request",
432-
error);
433+
proxy_connection_failed(exec_ctx, conn, SETUP_FAILED,
434+
"HTTP proxy read request", GRPC_ERROR_REF(error));
433435
GRPC_ERROR_UNREF(error);
434436
return;
435437
}
@@ -449,8 +451,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
449451
if (!client_authenticated) {
450452
const char* msg = "HTTP Connect could not verify authentication";
451453
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(msg);
452-
proxy_connection_failed(exec_ctx, conn, EP_FAIL,
453-
"HTTP proxy read request", error);
454+
proxy_connection_failed(exec_ctx, conn, SETUP_FAILED,
455+
"HTTP proxy read request", GRPC_ERROR_REF(error));
454456
GRPC_ERROR_UNREF(error);
455457
return;
456458
}
@@ -460,8 +462,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
460462
error = grpc_blocking_resolve_address(conn->http_request.path, "80",
461463
&resolved_addresses);
462464
if (error != GRPC_ERROR_NONE) {
463-
proxy_connection_failed(exec_ctx, conn, EP_FAIL, "HTTP proxy DNS lookup",
464-
error);
465+
proxy_connection_failed(exec_ctx, conn, SETUP_FAILED,
466+
"HTTP proxy DNS lookup", GRPC_ERROR_REF(error));
465467
GRPC_ERROR_UNREF(error);
466468
return;
467469
}

0 commit comments

Comments
 (0)