commit
08b0fab426
187 changed files with 15851 additions and 3328 deletions
@ -0,0 +1,15 @@ |
||||
There are times when we make changes that include a temporary shim for |
||||
backward-compatibility (e.g., a macro or some other function to preserve |
||||
the original API) to avoid having to bump the major version number in |
||||
the next release. However, when we do eventually want to release a |
||||
feature that does change the API in a non-backward-compatible way, we |
||||
will wind up bumping the major version number anyway, at which point we |
||||
can take the opportunity to clean up any pending backward-compatibility |
||||
shims. |
||||
|
||||
This file lists all pending backward-compatibility changes that should |
||||
be cleaned up the next time we are going to bump the major version |
||||
number: |
||||
|
||||
- remove `GRPC_ARG_MAX_MESSAGE_LENGTH` channel arg from |
||||
`include/grpc/impl/codegen/grpc_types.h` (commit `af00d8b`) |
@ -0,0 +1,192 @@ |
||||
# gRPC Server Reflection Tutorial |
||||
|
||||
gRPC Server Reflection provides information about publicly-accessible gRPC |
||||
services on a server, and assists clients at runtime to construct RPC |
||||
requests and responses without precompiled service information. It is used by |
||||
gRPC CLI, which can be used to introspect server protos and send/receive test |
||||
RPCs. |
||||
|
||||
## Enable Server Reflection |
||||
|
||||
### Enable server reflection in C++ servers |
||||
|
||||
C++ Server Reflection is an add-on library, `libgrpc++_reflction`. To enable C++ |
||||
server reflection, you can link this library to your server binary. |
||||
|
||||
Some platforms (e.g. Ubuntu 11.10 onwards) only link in libraries that directly |
||||
contain symbols used by the application. On these platforms, LD flag |
||||
`--no-as-needed` is needed for for dynamic linking and `--whole-archive` is |
||||
needed for for static linking. |
||||
|
||||
This [Makefile](../examples/cpp/helloworld/Makefile#L37#L45) demonstrates |
||||
enabling c++ server reflection on Linux and MacOS. |
||||
|
||||
## Test services using Server Reflection |
||||
|
||||
After enabling Server Reflection in a server application, you can use gRPC CLI |
||||
to test its services. |
||||
|
||||
Instructions on how to use gRPC CLI can be found at |
||||
[command_line_tool.md](command_line_tool.md), or using `grpc_cli help` command. |
||||
|
||||
Here we use `examples/cpp/helloworld` as an example to show the use of gRPC |
||||
Server Reflection and gRPC CLI. First, we need to build gRPC CLI and setup an |
||||
example server with Server Reflection enabled. |
||||
|
||||
- Setup an example server |
||||
|
||||
Server Reflection has already been enabled in the |
||||
[Makefile](../examples/cpp/helloworld/Makefile) of the helloworld example. We |
||||
can simply make it and run the greeter_server. |
||||
|
||||
```sh |
||||
$ make -C examples/cpp/helloworld |
||||
$ examples/cpp/helloworld/greeter_server & |
||||
``` |
||||
|
||||
- Build gRPC CLI |
||||
|
||||
```sh |
||||
make grpc_cli |
||||
cd bins/opt |
||||
``` |
||||
|
||||
gRPC CLI binary `grpc_cli` can be found at `bins/opt/` folder. This tool is |
||||
still new and does not have a `make install` target yet. |
||||
|
||||
### List services |
||||
|
||||
`grpc_cli ls` command lists services and methods exposed at a given port |
||||
|
||||
- List all the services exposed at a given port |
||||
|
||||
```sh |
||||
$ grpc_cli ls localhost:50051 |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
helloworld.Greeter |
||||
grpc.reflection.v1alpha.ServerReflection |
||||
``` |
||||
|
||||
- List one service with details |
||||
|
||||
`grpc_cli ls` command inspects a service given its full name (in the format of |
||||
\<package\>.\<service\>). It can print information with a long listing format |
||||
when `-l` flag is set. This flag can be used to get more details about a |
||||
service. |
||||
|
||||
```sh |
||||
$ grpc_cli ls localhost:50051 helloworld.Greeter -l |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
filename: helloworld.proto |
||||
package: helloworld; |
||||
service Greeter { |
||||
rpc SayHello(helloworld.HelloRequest) returns (helloworld.HelloReply) {} |
||||
} |
||||
|
||||
``` |
||||
|
||||
### List methods |
||||
|
||||
- List one method with details |
||||
|
||||
`grpc_cli ls` command also inspects a method given its full name (in the |
||||
format of \<package\>.\<service\>.\<method\>). |
||||
|
||||
```sh |
||||
$ grpc_cli ls localhost:50051 helloworld.Greeter.SayHello -l |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
rpc SayHello(helloworld.HelloRequest) returns (helloworld.HelloReply) {} |
||||
``` |
||||
|
||||
### Inspect message types |
||||
|
||||
We can use`grpc_cli type` command to inspect request/response types given the |
||||
full name of the type (in the format of \<package\>.\<type\>). |
||||
|
||||
- Get information about the request type |
||||
|
||||
```sh |
||||
$ grpc_cli type localhost:50051 helloworld.HelloRequest |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
message HelloRequest { |
||||
optional string name = 1; |
||||
} |
||||
``` |
||||
|
||||
### Call a remote method |
||||
|
||||
We can send RPCs to a server and get responses using `grpc_cli call` command. |
||||
|
||||
- Call a unary method |
||||
|
||||
```sh |
||||
$ grpc_cli call localhost:50051 SayHello "name: 'gRPC CLI'" |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
message: "Hello gRPC CLI" |
||||
``` |
||||
|
||||
## Use Server Reflection in a C++ client |
||||
|
||||
Server Reflection can be used by clients to get information about gRPC services |
||||
at runtime. We've provided a descriptor database called |
||||
[grpc::ProtoReflectionDescriptorDatabase](../test/cpp/util/proto_reflection_descriptor_database.h) |
||||
which implements the |
||||
[google::protobuf::DescriptorDatabase](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.descriptor_database#DescriptorDatabase) |
||||
interface. It manages the communication between clients and reflection services |
||||
and the storage of received information. Clients can use it as using a local |
||||
descriptor database. |
||||
|
||||
- To use Server Reflection with grpc::ProtoReflectionDescriptorDatabase, first |
||||
initialize an instance with a grpc::Channel. |
||||
|
||||
```c++ |
||||
std::shared_ptr<grpc::Channel> channel = |
||||
grpc::CreateChannel(server_address, server_cred); |
||||
grpc::ProtoReflectionDescriptorDatabase reflection_db(channel); |
||||
``` |
||||
|
||||
- Then use this instance to feed a |
||||
[google::protobuf::DescriptorPool](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.descriptor#DescriptorPool). |
||||
|
||||
```c++ |
||||
google::protobuf::DescriptorPool desc_pool(&reflection_db); |
||||
``` |
||||
|
||||
- Example usage of this descriptor pool |
||||
|
||||
* Get Service/method descriptors. |
||||
|
||||
```c++ |
||||
const google::protobuf::ServiceDescriptor* service_desc = |
||||
desc_pool->FindServiceByName("helloworld.Greeter"); |
||||
const google::protobuf::MethodDescriptor* method_desc = |
||||
desc_pool->FindMethodByName("helloworld.Greeter.SayHello"); |
||||
``` |
||||
|
||||
* Get message type descriptors. |
||||
|
||||
```c++ |
||||
const google::protobuf::Descriptor* request_desc = |
||||
desc_pool->FindMessageTypeByName("helloworld.HelloRequest"); |
||||
``` |
||||
|
||||
* Feed [google::protobuf::DynamicMessageFactory](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.dynamic_message#DynamicMessageFactory). |
||||
|
||||
```c++ |
||||
google::protobuf::DynamicMessageFactory(&desc_pool); |
||||
``` |
@ -0,0 +1,86 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/ext/census/trace_context.h" |
||||
|
||||
#include <grpc/census.h> |
||||
#include <grpc/support/log.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "third_party/nanopb/pb_decode.h" |
||||
#include "third_party/nanopb/pb_encode.h" |
||||
|
||||
// This function assumes the TraceContext is valid.
|
||||
size_t encode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer, |
||||
const size_t buf_size) { |
||||
// Create a stream that will write to our buffer.
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, buf_size); |
||||
|
||||
// encode message
|
||||
bool status = pb_encode(&stream, google_trace_TraceContext_fields, ctxt); |
||||
|
||||
if (!status) { |
||||
gpr_log(GPR_DEBUG, "TraceContext encoding failed: %s", |
||||
PB_GET_ERROR(&stream)); |
||||
return 0; |
||||
} |
||||
|
||||
return stream.bytes_written; |
||||
} |
||||
|
||||
bool decode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer, |
||||
const size_t nbytes) { |
||||
// Create a stream that reads nbytes from the buffer.
|
||||
pb_istream_t stream = pb_istream_from_buffer(buffer, nbytes); |
||||
|
||||
// decode message
|
||||
bool status = pb_decode(&stream, google_trace_TraceContext_fields, ctxt); |
||||
|
||||
if (!status) { |
||||
gpr_log(GPR_DEBUG, "TraceContext decoding failed: %s", |
||||
PB_GET_ERROR(&stream)); |
||||
return false; |
||||
} |
||||
|
||||
// check fields
|
||||
if (!ctxt->has_trace_id) { |
||||
gpr_log(GPR_DEBUG, "Invalid TraceContext: missing trace_id"); |
||||
return false; |
||||
} |
||||
if (!ctxt->has_span_id) { |
||||
gpr_log(GPR_DEBUG, "Invalid TraceContext: missing span_id"); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
@ -0,0 +1,68 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
/* Functions for manipulating trace contexts as defined in
|
||||
src/proto/census/trace.proto */ |
||||
#ifndef GRPC_CORE_EXT_CENSUS_TRACE_CONTEXT_H |
||||
#define GRPC_CORE_EXT_CENSUS_TRACE_CONTEXT_H |
||||
|
||||
#include "src/core/ext/census/gen/trace_context.pb.h" |
||||
|
||||
/* Maximum number of bytes required to encode a TraceContext (31)
|
||||
1 byte for trace_id field |
||||
1 byte for trace_id length |
||||
1 byte for trace_id.hi field |
||||
8 bytes for trace_id.hi (uint64_t) |
||||
1 byte for trace_id.lo field |
||||
8 bytes for trace_id.lo (uint64_t) |
||||
1 byte for span_id field |
||||
8 bytes for span_id (uint64_t) |
||||
1 byte for is_sampled field |
||||
1 byte for is_sampled (bool) */ |
||||
#define TRACE_MAX_CONTEXT_SIZE 31 |
||||
|
||||
/* Encode a trace context (ctxt) into proto format to the buffer provided. The
|
||||
size of buffer must be at least TRACE_MAX_CONTEXT_SIZE. On success, returns the |
||||
number of bytes successfully encoded into buffer. On failure, returns 0. */ |
||||
size_t encode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer, |
||||
const size_t buf_size); |
||||
|
||||
/* Decode a proto-encoded TraceContext from the provided buffer into the
|
||||
TraceContext structure (ctxt). The function expects to be supplied the number |
||||
of bytes to be read from buffer (nbytes). This function will also validate that |
||||
the TraceContext has a span_id and a trace_id, and will return false if either |
||||
of these do not exist. On success, returns true and false otherwise. */ |
||||
bool decode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer, |
||||
const size_t nbytes); |
||||
|
||||
#endif |
@ -0,0 +1,275 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/ext/client_config/http_connect_handshaker.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/slice_buffer.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/ext/client_config/uri_parser.h" |
||||
#include "src/core/lib/http/format_request.h" |
||||
#include "src/core/lib/http/parser.h" |
||||
#include "src/core/lib/iomgr/timer.h" |
||||
#include "src/core/lib/support/env.h" |
||||
|
||||
typedef struct http_connect_handshaker { |
||||
// Base class. Must be first.
|
||||
grpc_handshaker base; |
||||
|
||||
char* proxy_server; |
||||
char* server_name; |
||||
|
||||
// State saved while performing the handshake.
|
||||
grpc_endpoint* endpoint; |
||||
grpc_channel_args* args; |
||||
grpc_handshaker_done_cb cb; |
||||
void* user_data; |
||||
|
||||
// Objects for processing the HTTP CONNECT request and response.
|
||||
gpr_slice_buffer write_buffer; |
||||
gpr_slice_buffer* read_buffer; // Ownership passes through this object.
|
||||
grpc_closure request_done_closure; |
||||
grpc_closure response_read_closure; |
||||
grpc_http_parser http_parser; |
||||
grpc_http_response http_response; |
||||
grpc_timer timeout_timer; |
||||
|
||||
gpr_refcount refcount; |
||||
} http_connect_handshaker; |
||||
|
||||
// Unref and clean up handshaker.
|
||||
static void http_connect_handshaker_unref(http_connect_handshaker* handshaker) { |
||||
if (gpr_unref(&handshaker->refcount)) { |
||||
gpr_free(handshaker->proxy_server); |
||||
gpr_free(handshaker->server_name); |
||||
gpr_slice_buffer_destroy(&handshaker->write_buffer); |
||||
grpc_http_parser_destroy(&handshaker->http_parser); |
||||
grpc_http_response_destroy(&handshaker->http_response); |
||||
gpr_free(handshaker); |
||||
} |
||||
} |
||||
|
||||
// Callback invoked when deadline is exceeded.
|
||||
static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { |
||||
http_connect_handshaker* handshaker = arg; |
||||
if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled.
|
||||
grpc_endpoint_shutdown(exec_ctx, handshaker->endpoint); |
||||
} |
||||
http_connect_handshaker_unref(handshaker); |
||||
} |
||||
|
||||
// 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* handshaker = arg; |
||||
if (error != GRPC_ERROR_NONE) { |
||||
// If the write failed, invoke the callback immediately with the error.
|
||||
handshaker->cb(exec_ctx, handshaker->endpoint, handshaker->args, |
||||
handshaker->read_buffer, handshaker->user_data, |
||||
GRPC_ERROR_REF(error)); |
||||
} else { |
||||
// Otherwise, read the response.
|
||||
grpc_endpoint_read(exec_ctx, handshaker->endpoint, handshaker->read_buffer, |
||||
&handshaker->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* handshaker = arg; |
||||
if (error != GRPC_ERROR_NONE) { |
||||
GRPC_ERROR_REF(error); // Take ref to pass to the handshake-done callback.
|
||||
goto done; |
||||
} |
||||
// Add buffer to parser.
|
||||
for (size_t i = 0; i < handshaker->read_buffer->count; ++i) { |
||||
if (GPR_SLICE_LENGTH(handshaker->read_buffer->slices[i]) > 0) { |
||||
size_t body_start_offset = 0; |
||||
error = grpc_http_parser_parse(&handshaker->http_parser, |
||||
handshaker->read_buffer->slices[i], |
||||
&body_start_offset); |
||||
if (error != GRPC_ERROR_NONE) goto done; |
||||
if (handshaker->http_parser.state == GRPC_HTTP_BODY) { |
||||
// We've gotten back a successul response, so stop the timeout timer.
|
||||
grpc_timer_cancel(exec_ctx, &handshaker->timeout_timer); |
||||
// Remove the data we've already read from the read buffer,
|
||||
// leaving only the leftover bytes (if any).
|
||||
gpr_slice_buffer tmp_buffer; |
||||
gpr_slice_buffer_init(&tmp_buffer); |
||||
if (body_start_offset < |
||||
GPR_SLICE_LENGTH(handshaker->read_buffer->slices[i])) { |
||||
gpr_slice_buffer_add( |
||||
&tmp_buffer, |
||||
gpr_slice_split_tail(&handshaker->read_buffer->slices[i], |
||||
body_start_offset)); |
||||
} |
||||
gpr_slice_buffer_addn(&tmp_buffer, |
||||
&handshaker->read_buffer->slices[i + 1], |
||||
handshaker->read_buffer->count - i - 1); |
||||
gpr_slice_buffer_swap(handshaker->read_buffer, &tmp_buffer); |
||||
gpr_slice_buffer_destroy(&tmp_buffer); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
// 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 (handshaker->http_parser.state != GRPC_HTTP_BODY) { |
||||
gpr_slice_buffer_reset_and_unref(handshaker->read_buffer); |
||||
grpc_endpoint_read(exec_ctx, handshaker->endpoint, handshaker->read_buffer, |
||||
&handshaker->response_read_closure); |
||||
return; |
||||
} |
||||
// Make sure we got a 2xx response.
|
||||
if (handshaker->http_response.status < 200 || |
||||
handshaker->http_response.status >= 300) { |
||||
char* msg; |
||||
gpr_asprintf(&msg, "HTTP proxy returned response code %d", |
||||
handshaker->http_response.status); |
||||
error = GRPC_ERROR_CREATE(msg); |
||||
gpr_free(msg); |
||||
} |
||||
done: |
||||
// Invoke handshake-done callback.
|
||||
handshaker->cb(exec_ctx, handshaker->endpoint, handshaker->args, |
||||
handshaker->read_buffer, handshaker->user_data, error); |
||||
} |
||||
|
||||
//
|
||||
// Public handshaker methods
|
||||
//
|
||||
|
||||
static void http_connect_handshaker_destroy(grpc_exec_ctx* exec_ctx, |
||||
grpc_handshaker* handshaker_in) { |
||||
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in; |
||||
http_connect_handshaker_unref(handshaker); |
||||
} |
||||
|
||||
static void http_connect_handshaker_shutdown(grpc_exec_ctx* exec_ctx, |
||||
grpc_handshaker* handshaker) {} |
||||
|
||||
static void http_connect_handshaker_do_handshake( |
||||
grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker_in, |
||||
grpc_endpoint* endpoint, grpc_channel_args* args, |
||||
gpr_slice_buffer* read_buffer, gpr_timespec deadline, |
||||
grpc_tcp_server_acceptor* acceptor, grpc_handshaker_done_cb cb, |
||||
void* user_data) { |
||||
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in; |
||||
// Save state in the handshaker object.
|
||||
handshaker->endpoint = endpoint; |
||||
handshaker->args = args; |
||||
handshaker->cb = cb; |
||||
handshaker->user_data = user_data; |
||||
handshaker->read_buffer = read_buffer; |
||||
// Send HTTP CONNECT request.
|
||||
gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s", |
||||
handshaker->server_name, handshaker->proxy_server); |
||||
grpc_httpcli_request request; |
||||
memset(&request, 0, sizeof(request)); |
||||
request.host = handshaker->proxy_server; |
||||
request.http.method = "CONNECT"; |
||||
request.http.path = handshaker->server_name; |
||||
request.handshaker = &grpc_httpcli_plaintext; |
||||
gpr_slice request_slice = grpc_httpcli_format_connect_request(&request); |
||||
gpr_slice_buffer_add(&handshaker->write_buffer, request_slice); |
||||
grpc_endpoint_write(exec_ctx, endpoint, &handshaker->write_buffer, |
||||
&handshaker->request_done_closure); |
||||
// Set timeout timer. The timer gets a reference to the handshaker.
|
||||
gpr_ref(&handshaker->refcount); |
||||
grpc_timer_init(exec_ctx, &handshaker->timeout_timer, |
||||
gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), |
||||
on_timeout, handshaker, gpr_now(GPR_CLOCK_MONOTONIC)); |
||||
} |
||||
|
||||
static const struct grpc_handshaker_vtable http_connect_handshaker_vtable = { |
||||
http_connect_handshaker_destroy, http_connect_handshaker_shutdown, |
||||
http_connect_handshaker_do_handshake}; |
||||
|
||||
grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server, |
||||
const char* server_name) { |
||||
GPR_ASSERT(proxy_server != NULL); |
||||
GPR_ASSERT(server_name != NULL); |
||||
http_connect_handshaker* handshaker = |
||||
gpr_malloc(sizeof(http_connect_handshaker)); |
||||
memset(handshaker, 0, sizeof(*handshaker)); |
||||
grpc_handshaker_init(&http_connect_handshaker_vtable, &handshaker->base); |
||||
handshaker->proxy_server = gpr_strdup(proxy_server); |
||||
handshaker->server_name = gpr_strdup(server_name); |
||||
gpr_slice_buffer_init(&handshaker->write_buffer); |
||||
grpc_closure_init(&handshaker->request_done_closure, on_write_done, |
||||
handshaker); |
||||
grpc_closure_init(&handshaker->response_read_closure, on_read_done, |
||||
handshaker); |
||||
grpc_http_parser_init(&handshaker->http_parser, GRPC_HTTP_RESPONSE, |
||||
&handshaker->http_response); |
||||
gpr_ref_init(&handshaker->refcount, 1); |
||||
return &handshaker->base; |
||||
} |
||||
|
||||
char* grpc_get_http_proxy_server() { |
||||
char* uri_str = gpr_getenv("http_proxy"); |
||||
if (uri_str == NULL) return NULL; |
||||
grpc_uri* uri = grpc_uri_parse(uri_str, false /* suppress_errors */); |
||||
char* proxy_name = NULL; |
||||
if (uri == NULL || uri->authority == NULL) { |
||||
gpr_log(GPR_ERROR, "cannot parse value of 'http_proxy' env var"); |
||||
goto done; |
||||
} |
||||
if (strcmp(uri->scheme, "http") != 0) { |
||||
gpr_log(GPR_ERROR, "'%s' scheme not supported in proxy URI", uri->scheme); |
||||
goto done; |
||||
} |
||||
if (strchr(uri->authority, '@') != NULL) { |
||||
gpr_log(GPR_ERROR, "userinfo not supported in proxy URI"); |
||||
goto done; |
||||
} |
||||
proxy_name = gpr_strdup(uri->authority); |
||||
done: |
||||
gpr_free(uri_str); |
||||
grpc_uri_destroy(uri); |
||||
return proxy_name; |
||||
} |
@ -0,0 +1,47 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_HTTP_CONNECT_HANDSHAKER_H |
||||
#define GRPC_CORE_EXT_CLIENT_CONFIG_HTTP_CONNECT_HANDSHAKER_H |
||||
|
||||
#include "src/core/lib/channel/handshaker.h" |
||||
|
||||
/// Does NOT take ownership of \a proxy_server or \a server_name.
|
||||
grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server, |
||||
const char* server_name); |
||||
|
||||
/// Returns the name of the proxy to use, or NULL if no proxy is configured.
|
||||
/// Caller takes ownership of result.
|
||||
char* grpc_get_http_proxy_server(); |
||||
|
||||
#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_HTTP_CONNECT_HANDSHAKER_H */ |
@ -1,75 +1,94 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
//
|
||||
// Copyright 2015, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "src/core/ext/client_config/resolver_result.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
|
||||
struct grpc_resolver_result { |
||||
gpr_refcount refs; |
||||
grpc_lb_policy *lb_policy; |
||||
char* server_name; |
||||
grpc_lb_addresses* addresses; |
||||
char* lb_policy_name; |
||||
grpc_channel_args* lb_policy_args; |
||||
}; |
||||
|
||||
grpc_resolver_result *grpc_resolver_result_create() { |
||||
grpc_resolver_result *c = gpr_malloc(sizeof(*c)); |
||||
memset(c, 0, sizeof(*c)); |
||||
gpr_ref_init(&c->refs, 1); |
||||
return c; |
||||
grpc_resolver_result* grpc_resolver_result_create( |
||||
const char* server_name, grpc_lb_addresses* addresses, |
||||
const char* lb_policy_name, grpc_channel_args* lb_policy_args) { |
||||
grpc_resolver_result* result = gpr_malloc(sizeof(*result)); |
||||
memset(result, 0, sizeof(*result)); |
||||
gpr_ref_init(&result->refs, 1); |
||||
result->server_name = gpr_strdup(server_name); |
||||
result->addresses = addresses; |
||||
result->lb_policy_name = gpr_strdup(lb_policy_name); |
||||
result->lb_policy_args = lb_policy_args; |
||||
return result; |
||||
} |
||||
|
||||
void grpc_resolver_result_ref(grpc_resolver_result *c) { gpr_ref(&c->refs); } |
||||
void grpc_resolver_result_ref(grpc_resolver_result* result) { |
||||
gpr_ref(&result->refs); |
||||
} |
||||
|
||||
void grpc_resolver_result_unref(grpc_exec_ctx *exec_ctx, |
||||
grpc_resolver_result *c) { |
||||
if (gpr_unref(&c->refs)) { |
||||
if (c->lb_policy != NULL) { |
||||
GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "resolver_result"); |
||||
} |
||||
gpr_free(c); |
||||
void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx, |
||||
grpc_resolver_result* result) { |
||||
if (gpr_unref(&result->refs)) { |
||||
gpr_free(result->server_name); |
||||
grpc_lb_addresses_destroy(result->addresses, NULL /* user_data_destroy */); |
||||
gpr_free(result->lb_policy_name); |
||||
grpc_channel_args_destroy(result->lb_policy_args); |
||||
gpr_free(result); |
||||
} |
||||
} |
||||
|
||||
void grpc_resolver_result_set_lb_policy(grpc_resolver_result *c, |
||||
grpc_lb_policy *lb_policy) { |
||||
GPR_ASSERT(c->lb_policy == NULL); |
||||
if (lb_policy) { |
||||
GRPC_LB_POLICY_REF(lb_policy, "resolver_result"); |
||||
} |
||||
c->lb_policy = lb_policy; |
||||
const char* grpc_resolver_result_get_server_name(grpc_resolver_result* result) { |
||||
return result->server_name; |
||||
} |
||||
|
||||
grpc_lb_addresses* grpc_resolver_result_get_addresses( |
||||
grpc_resolver_result* result) { |
||||
return result->addresses; |
||||
} |
||||
|
||||
const char* grpc_resolver_result_get_lb_policy_name( |
||||
grpc_resolver_result* result) { |
||||
return result->lb_policy_name; |
||||
} |
||||
|
||||
grpc_lb_policy *grpc_resolver_result_get_lb_policy(grpc_resolver_result *c) { |
||||
return c->lb_policy; |
||||
grpc_channel_args* grpc_resolver_result_get_lb_policy_args( |
||||
grpc_resolver_result* result) { |
||||
return result->lb_policy_args; |
||||
} |
||||
|
@ -1,52 +1,74 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
//
|
||||
// Copyright 2015, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H |
||||
#define GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H |
||||
|
||||
#include "src/core/ext/client_config/lb_policy.h" |
||||
#include "src/core/ext/client_config/lb_policy_factory.h" |
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
|
||||
/** Results reported from a grpc_resolver. */ |
||||
// TODO(roth, ctiller): In the long term, we are considering replacing
|
||||
// the resolver_result data structure with grpc_channel_args. The idea is
|
||||
// that the resolver will return a set of channel args that contains the
|
||||
// information that is currently in the resolver_result struct. For
|
||||
// example, there will be specific args indicating the set of addresses
|
||||
// and the name of the LB policy to instantiate. Note that if we did
|
||||
// this, we would probably want to change the data structure of
|
||||
// grpc_channel_args such to a hash table or AVL or some other data
|
||||
// structure that does not require linear search to find keys.
|
||||
|
||||
/// Results reported from a grpc_resolver.
|
||||
typedef struct grpc_resolver_result grpc_resolver_result; |
||||
|
||||
grpc_resolver_result *grpc_resolver_result_create(); |
||||
void grpc_resolver_result_ref(grpc_resolver_result *client_config); |
||||
void grpc_resolver_result_unref(grpc_exec_ctx *exec_ctx, |
||||
grpc_resolver_result *client_config); |
||||
/// Takes ownership of \a addresses and \a lb_policy_args.
|
||||
grpc_resolver_result* grpc_resolver_result_create( |
||||
const char* server_name, grpc_lb_addresses* addresses, |
||||
const char* lb_policy_name, grpc_channel_args* lb_policy_args); |
||||
void grpc_resolver_result_ref(grpc_resolver_result* result); |
||||
void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx, |
||||
grpc_resolver_result* result); |
||||
|
||||
/// Caller does NOT take ownership of result.
|
||||
const char* grpc_resolver_result_get_server_name(grpc_resolver_result* result); |
||||
|
||||
/// Caller does NOT take ownership of result.
|
||||
grpc_lb_addresses* grpc_resolver_result_get_addresses( |
||||
grpc_resolver_result* result); |
||||
|
||||
/// Caller does NOT take ownership of result.
|
||||
const char* grpc_resolver_result_get_lb_policy_name( |
||||
grpc_resolver_result* result); |
||||
|
||||
void grpc_resolver_result_set_lb_policy(grpc_resolver_result *client_config, |
||||
grpc_lb_policy *lb_policy); |
||||
grpc_lb_policy *grpc_resolver_result_get_lb_policy( |
||||
grpc_resolver_result *client_config); |
||||
/// Caller does NOT take ownership of result.
|
||||
grpc_channel_args* grpc_resolver_result_get_lb_policy_args( |
||||
grpc_resolver_result* result); |
||||
|
||||
#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H */ |
||||
|
@ -0,0 +1,165 @@ |
||||
//
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "src/core/lib/channel/message_size_filter.h" |
||||
|
||||
#include <limits.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
|
||||
// The protobuf library will (by default) start warning at 100 megs.
|
||||
#define DEFAULT_MAX_MESSAGE_LENGTH (4 * 1024 * 1024) |
||||
|
||||
typedef struct call_data { |
||||
// Receive closures are chained: we inject this closure as the
|
||||
// recv_message_ready up-call on transport_stream_op, and remember to
|
||||
// call our next_recv_message_ready member after handling it.
|
||||
grpc_closure recv_message_ready; |
||||
// Used by recv_message_ready.
|
||||
grpc_byte_stream** recv_message; |
||||
// Original recv_message_ready callback, invoked after our own.
|
||||
grpc_closure* next_recv_message_ready; |
||||
} call_data; |
||||
|
||||
typedef struct channel_data { |
||||
size_t max_send_size; |
||||
size_t max_recv_size; |
||||
} channel_data; |
||||
|
||||
// Callback invoked when we receive a message. Here we check the max
|
||||
// receive message size.
|
||||
static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data, |
||||
grpc_error* error) { |
||||
grpc_call_element* elem = user_data; |
||||
call_data* calld = elem->call_data; |
||||
channel_data* chand = elem->channel_data; |
||||
if (*calld->recv_message != NULL && |
||||
(*calld->recv_message)->length > chand->max_recv_size) { |
||||
char* message_string; |
||||
gpr_asprintf( |
||||
&message_string, "Received message larger than max (%u vs. %lu)", |
||||
(*calld->recv_message)->length, (unsigned long)chand->max_recv_size); |
||||
gpr_slice message = gpr_slice_from_copied_string(message_string); |
||||
gpr_free(message_string); |
||||
grpc_call_element_send_cancel_with_message( |
||||
exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, &message); |
||||
} |
||||
// Invoke the next callback.
|
||||
grpc_exec_ctx_sched(exec_ctx, calld->next_recv_message_ready, error, NULL); |
||||
} |
||||
|
||||
// Start transport op.
|
||||
static void start_transport_stream_op(grpc_exec_ctx* exec_ctx, |
||||
grpc_call_element* elem, |
||||
grpc_transport_stream_op* op) { |
||||
call_data* calld = elem->call_data; |
||||
channel_data* chand = elem->channel_data; |
||||
// Check max send message size.
|
||||
if (op->send_message != NULL && |
||||
op->send_message->length > chand->max_send_size) { |
||||
char* message_string; |
||||
gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %lu)", |
||||
op->send_message->length, (unsigned long)chand->max_send_size); |
||||
gpr_slice message = gpr_slice_from_copied_string(message_string); |
||||
gpr_free(message_string); |
||||
grpc_call_element_send_cancel_with_message( |
||||
exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, &message); |
||||
} |
||||
// Inject callback for receiving a message.
|
||||
if (op->recv_message_ready != NULL) { |
||||
calld->next_recv_message_ready = op->recv_message_ready; |
||||
calld->recv_message = op->recv_message; |
||||
op->recv_message_ready = &calld->recv_message_ready; |
||||
} |
||||
// Chain to the next filter.
|
||||
grpc_call_next_op(exec_ctx, elem, op); |
||||
} |
||||
|
||||
// Constructor for call_data.
|
||||
static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, |
||||
grpc_call_element* elem, |
||||
grpc_call_element_args* args) { |
||||
call_data* calld = elem->call_data; |
||||
calld->next_recv_message_ready = NULL; |
||||
grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem); |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
// Destructor for call_data.
|
||||
static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, |
||||
const grpc_call_final_info* final_info, |
||||
void* ignored) {} |
||||
|
||||
// Constructor for channel_data.
|
||||
static void init_channel_elem(grpc_exec_ctx* exec_ctx, |
||||
grpc_channel_element* elem, |
||||
grpc_channel_element_args* args) { |
||||
GPR_ASSERT(!args->is_last); |
||||
channel_data* chand = elem->channel_data; |
||||
memset(chand, 0, sizeof(*chand)); |
||||
chand->max_send_size = DEFAULT_MAX_MESSAGE_LENGTH; |
||||
chand->max_recv_size = DEFAULT_MAX_MESSAGE_LENGTH; |
||||
const grpc_integer_options options = {DEFAULT_MAX_MESSAGE_LENGTH, 0, INT_MAX}; |
||||
for (size_t i = 0; i < args->channel_args->num_args; ++i) { |
||||
if (strcmp(args->channel_args->args[i].key, |
||||
GRPC_ARG_MAX_SEND_MESSAGE_LENGTH) == 0) { |
||||
chand->max_send_size = (size_t)grpc_channel_arg_get_integer( |
||||
&args->channel_args->args[i], options); |
||||
} |
||||
if (strcmp(args->channel_args->args[i].key, |
||||
GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH) == 0) { |
||||
chand->max_recv_size = (size_t)grpc_channel_arg_get_integer( |
||||
&args->channel_args->args[i], options); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Destructor for channel_data.
|
||||
static void destroy_channel_elem(grpc_exec_ctx* exec_ctx, |
||||
grpc_channel_element* elem) {} |
||||
|
||||
const grpc_channel_filter grpc_message_size_filter = { |
||||
start_transport_stream_op, |
||||
grpc_channel_next_op, |
||||
sizeof(call_data), |
||||
init_call_elem, |
||||
grpc_call_stack_ignore_set_pollset_or_pollset_set, |
||||
destroy_call_elem, |
||||
sizeof(channel_data), |
||||
init_channel_elem, |
||||
destroy_channel_elem, |
||||
grpc_call_next_get_peer, |
||||
"message_size"}; |
@ -0,0 +1,39 @@ |
||||
//
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H |
||||
#define GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H |
||||
|
||||
#include "src/core/lib/channel/channel_stack.h" |
||||
|
||||
extern const grpc_channel_filter grpc_message_size_filter; |
||||
|
||||
#endif /* GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue