From d78e7ecf27e2d1bd8ce3566c13acc3463793c1b1 Mon Sep 17 00:00:00 2001 From: Ludovic Barman Date: Thu, 26 Oct 2023 12:59:04 +0000 Subject: Upgrade grpcio to 0.13.0 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update rust/crates/grpcio For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md Test: TreeHugger Change-Id: I9c3e5650701c9eced41ccd1a0ff85efb9c6f2664 --- .cargo_vcs_info.json | 7 ++- .clang-format | 39 +++++++++++- .clang-tidy | 27 ++++++--- .github/workflows/31167.supp | 1 + .github/workflows/ci.yml | 30 ++++++---- Android.bp | 6 +- CHANGELOG.md | 8 +++ Cargo.toml | 10 +++- Cargo.toml.orig | 8 ++- METADATA | 12 ++-- README.md | 8 +-- src/auth_context.rs | 139 ------------------------------------------- src/call/server.rs | 9 +-- src/channel.rs | 2 +- src/codec.rs | 22 +++++-- src/error.rs | 5 +- src/lib.rs | 4 +- src/log_util.rs | 4 +- src/metadata.rs | 6 +- src/security/auth_context.rs | 139 +++++++++++++++++++++++++++++++++++++++++++ src/security/mod.rs | 5 ++ 21 files changed, 292 insertions(+), 199 deletions(-) create mode 100644 .github/workflows/31167.supp delete mode 100644 src/auth_context.rs create mode 100644 src/security/auth_context.rs diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 4f6a222..9db2389 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "61a60923255fe618589bf03ece46fff097b8cb43" - } -} + "sha1": "5442991f322901d28e318bac5736abe13a10794c" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/.clang-format b/.clang-format index 7460950..608eea1 100644 --- a/.clang-format +++ b/.clang-format @@ -3,7 +3,44 @@ Language: Cpp BasedOnStyle: Google DerivePointerAlignment: false PointerAlignment: Left -IncludeBlocks: Preserve +IncludeBlocks: Regroup +IncludeCategories: + # port_platform.h is before almost everything + - Regex: '^' + Priority: -100 + # ruby.h is even more first if it's included + - Regex: '^' + Priority: -200 + # Some platforms (namely msys) need wchar to be included BEFORE + # anything else, especially strsafe.h. + - Regex: '^' + Priority: 5 + # use priority 100+ for grpc headers so they sort last + # 'system' headers - include things that have " in the names to make them + # stand out and get fixed + - Regex: '^(<|")grpc' + Priority: 100 + # similary using include/ to get system headers should stand out and get + # fixed + - Regex: '^"include/' + Priority: 100 + # source headers go last + - Regex: '^"(src|test)/' + Priority: 101 + # not-grpc headers follow + # first, non system headers that are included like <> - these are all + # local carveouts, and get sorted below c++ but before non grpc "" files + - Regex: '^<(openssl/|uv\.h|ares\.h|address_sorting/|gmock/|gtest/|zlib|zconf|benchmark/|google/)' + Priority: 30 + # first C system headers - they have a . in the filename + - Regex: '^<.*\.' + Priority: 10 + # then C++ system headers - no ., the only thing that will match now + - Regex: '^<' + Priority: 20 + # finally other "" includes go between system headers and our headers + - Regex: '^"' + Priority: 40 --- Language: ObjC BasedOnStyle: Google diff --git a/.clang-tidy b/.clang-tidy index 8714bad..03f4fcd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -7,9 +7,6 @@ # - bugprone-reserved-identifier # Some macros need to be defined for portability purpose; e.g. _BSD_SOURCE. # -# - google-upgrade-googletest-case -# This requires googletest 1.10 which is higher than ones installed on many linux distributions. -# # - modernize-redundant-void-arg # Some source should be strictly C99 and func(void) should be used. # @@ -17,16 +14,19 @@ # it's not activated yet due to the existing issues with the checks. # Once those issues are clear, these checks can be enabled later. # +# - bugprone-assignment-in-if-condition # - bugprone-branch-clone +# - bugprone-easily-swappable-parameters +# - bugprone-implicit-widening-of-multiplication-result # - bugprone-infinite-loop # - bugprone-narrowing-conversions # - bugprone-not-null-terminated-result # - bugprone-signed-char-misuse # - bugprone-sizeof-expression # - bugprone-too-small-loop-variable +# - bugprone-unchecked-optional-access # - clang-diagnostic-deprecated-declarations # - clang-diagnostic-unused-function -# - google-readability-avoid-underscore-in-googletest-name # - google-runtime-int # - google-runtime-references # - modernize-avoid-bind @@ -42,18 +42,21 @@ # - modernize-use-equals-delete # - modernize-use-using # - performance-no-automatic-move +# - performance-no-int-to-ptr # - performance-unnecessary-copy-initialization # - performance-unnecessary-value-param # - readability-else-after-return # - readability-implicit-bool-conversion # - readability-redundant-declaration -# - readability-static-definition-in-anonymous-namespace # Checks: '-*, abseil-*, -abseil-no-namespace, bugprone-*, + -bugprone-assignment-in-if-condition, -bugprone-branch-clone, + -bugprone-easily-swappable-parameters, + -bugprone-implicit-widening-of-multiplication-result, -bugprone-infinite-loop, -bugprone-narrowing-conversions, -bugprone-not-null-terminated-result, @@ -61,13 +64,13 @@ Checks: '-*, -bugprone-signed-char-misuse, -bugprone-sizeof-expression, -bugprone-too-small-loop-variable, + -bugprone-unchecked-optional-access, google-*, - -google-readability-avoid-underscore-in-googletest-name, -google-runtime-int, -google-runtime-references, - -google-upgrade-googletest-case, performance-*, -performance-no-automatic-move, + -performance-no-int-to-ptr, -performance-unnecessary-copy-initialization, -performance-unnecessary-value-param, clang-diagnostic-deprecated-register, @@ -103,18 +106,24 @@ Checks: '-*, modernize-use-nullptr, modernize-use-override, modernize-use-transparent-functors, + readability-braces-around-statements, readability-const-return-type, readability-container-size-empty, readability-delete-null-pointer, readability-deleted-default, + readability-duplicate-include, readability-function-size, readability-inconsistent-declaration-parameter-name, readability-misleading-indentation, readability-misplaced-array-index, + readability-redundant-access-specifiers, readability-redundant-control-flow, readability-redundant-function-ptr-dereference, readability-redundant-smartptr-get, + readability-redundant-string-cstr, + readability-redundant-string-init, readability-simplify-boolean-expr, + readability-static-definition-in-anonymous-namespace, readability-string-compare, readability-uniqueptr-delete-release' WarningsAsErrors: '*' @@ -125,5 +134,7 @@ CheckOptions: value: 'absl::make_unique' - key: modernize-make-unique.MakeSmartPtrFunctionHeader value: 'absl/memory/memory.h' - - key: google-readability-braces-around-statements.ShortStatementLines + - key: readability-braces-around-statements.ShortStatementLines value: 1 + - key: readability-simplify-boolean-expr.SimplifyDeMorgan + value: false diff --git a/.github/workflows/31167.supp b/.github/workflows/31167.supp new file mode 100644 index 0000000..6a85e57 --- /dev/null +++ b/.github/workflows/31167.supp @@ -0,0 +1 @@ +interceptor_via_fun:grpc_error_set_str diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f25093f..8adc32e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: push: branches: - master + - v0.* schedule: - cron: '0 22 * * *' @@ -13,6 +14,7 @@ env: # Some of the bindgen tests generate "deref-nullptr" warnings, see https://github.com/rust-lang/rust-bindgen/issues/1651 RUSTFLAGS: "--deny=warnings --allow deref-nullptr" TEST_BIND: 1 + GRPC_VERBOSITY: "info" jobs: Linux-Format: @@ -20,8 +22,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - run: sudo apt-get install -y clang-tidy-9 - - run: sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-9 100 - run: which cargo && cargo version && clang --version && openssl version && which cmake && cmake --version - run: cargo xtask submodule - run: cargo fmt --all -- --check @@ -35,9 +35,6 @@ jobs: - host: ubuntu-latest profile: suffix: - - host: ARM64 - profile: --release - suffix: -Arm64 name: Linux-Stable${{ matrix.suffix }} runs-on: ${{ matrix.host }} steps: @@ -50,6 +47,7 @@ jobs: - run: cargo xtask bindgen - run: cargo build --no-default-features - run: cargo build --no-default-features --features protobuf-codec + - run: cargo build --no-default-features --features protobufv3-codec - run: cargo build --no-default-features --features prost-codec - run: cd proto && cargo build --no-default-features --features prost-codec - run: cargo build @@ -62,9 +60,6 @@ jobs: - host: ubuntu-latest profile: suffix: - - host: ARM64 - profile: --release - suffix: -Arm64 name: Linux-Stable-openssl${{ matrix.suffix }} runs-on: ${{ matrix.host }} steps: @@ -81,14 +76,18 @@ jobs: steps: - uses: actions/checkout@v2 - run: rustup default nightly + - run: sudo ln -s /usr/bin/llvm-symbolizer-14 /usr/bin/llvm-symbolizer - run: which cargo && cargo version && clang --version && openssl version - run: cargo xtask submodule - run: cargo build --no-default-features - run: cargo build --no-default-features --features protobuf-codec + - run: cargo build --no-default-features --features protobufv3-codec - run: cargo build --no-default-features --features prost-codec - run: cargo build - run: cargo test --all - - run: RUSTFLAGS="-Z sanitizer=address" cargo test --all --target x86_64-unknown-linux-gnu + # See https://github.com/grpc/grpc/pull/31167 + - run: RUSTFLAGS="-Z sanitizer=address" ASAN_OPTIONS=suppressions=`pwd`/.github/workflows/31167.supp cargo test --all --target x86_64-unknown-linux-gnu + - run: cargo test --features "nightly" Mac: name: Mac @@ -97,11 +96,15 @@ jobs: - uses: actions/checkout@v2 - run: which cargo && cargo version && clang --version && openssl version - run: cargo xtask submodule - - run: cargo build --no-default-features --features use-bindgen - - run: cargo build --no-default-features --features "protobuf-codec use-bindgen" - - run: cargo build --no-default-features --features "prost-codec use-bindgen" + - run: env TEST_BIND=0 cargo xtask bindgen && git diff --exit-code HEAD + - run: cargo xtask bindgen + - run: cargo build --no-default-features + - run: cargo build --no-default-features --features "protobuf-codec" + - run: cargo build --no-default-features --features "protobufv3-codec" + - run: cargo build --no-default-features --features "prost-codec" - run: cargo build - run: cargo test --all + - run: cargo test --features "nightly" Mac-openssl: name: Mac-openssl @@ -123,11 +126,12 @@ jobs: steps: - uses: actions/checkout@v2 - run: choco install -y llvm - - run: refreshenv + - run: Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 - run: go version ; cargo version ; cmake --version - run: cargo xtask submodule - run: cargo build - run: cargo test --all + - run: cargo test --features "nightly" Pre-Release: name: Pre-Release diff --git a/Android.bp b/Android.bp index a8a507d..2fb65f0 100644 --- a/Android.bp +++ b/Android.bp @@ -20,11 +20,10 @@ license { rust_library { name: "libgrpcio", - // has rustc warnings host_supported: true, crate_name: "grpcio", cargo_env_compat: true, - cargo_pkg_version: "0.12.1", + cargo_pkg_version: "0.13.0", srcs: ["src/lib.rs"], edition: "2018", features: [ @@ -34,8 +33,8 @@ rust_library { "protobuf-codec", ], rustlibs: [ - "libfutures_util", "libfutures_executor", + "libfutures_util", "libgrpcio_sys", "liblibc", "liblog_rust", @@ -45,7 +44,6 @@ rust_library { apex_available: [ "//apex_available:platform", ], - product_available: false, vendor_available: true, min_sdk_version: "29", } diff --git a/CHANGELOG.md b/CHANGELOG.md index 2899f77..4d7e4e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 0.13.0 - 2023-08-17 + +- Publicize prost service generator (#612) +- Update grpc to 1.56.2 (#621) (#624) (#629) +- Fix unknown log file and module in slog (#623) +- gate auth context under _secure feature (#622) +- rust-protobuf 3 support (#615) + # 0.12.1 - 2023-02-14 - Provide more debug info for RpcStatus (#603) diff --git a/Cargo.toml b/Cargo.toml index 83a57dd..ec94fdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "grpcio" -version = "0.12.1" +version = "0.13.0" authors = ["The TiKV Project Developers"] autoexamples = false description = "The rust language implementation of gRPC, base on the gRPC c core library." @@ -52,7 +52,7 @@ features = [ default-features = false [dependencies.grpcio-sys] -version = "0.12.1" +version = "0.13.0" default-features = false [dependencies.libc] @@ -72,6 +72,11 @@ optional = true version = "2.0" optional = true +[dependencies.protobufv3] +version = "3.2" +optional = true +package = "protobuf" + [features] _secure = [] boringssl = [ @@ -97,6 +102,7 @@ prost-codec = [ "bytes", ] protobuf-codec = ["protobuf"] +protobufv3-codec = ["protobufv3"] [badges.travis-ci] repository = "tikv/grpc-rs" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 68067cf..2334a42 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "grpcio" -version = "0.12.1" +version = "0.13.0" edition = "2018" authors = ["The TiKV Project Developers"] license = "Apache-2.0" @@ -17,11 +17,12 @@ autoexamples = false all-features = true [dependencies] -grpcio-sys = { path = "grpc-sys", version = "0.12.1", default-features = false } +grpcio-sys = { path = "grpc-sys", version = "0.13.0", default-features = false } libc = "0.2" futures-executor = "0.3" futures-util = { version = "0.3", default-features = false, features = ["std", "sink"] } protobuf = { version = "2.0", optional = true } +protobufv3 = { package = "protobuf", version = "3.2", optional = true } prost = { version = "0.11", optional = true } bytes = { version = "1.0", optional = true } log = "0.4" @@ -44,6 +45,7 @@ exclude = ["xtask"] default = ["protobuf-codec", "boringssl"] _secure = [] protobuf-codec = ["protobuf"] +protobufv3-codec = ["protobufv3"] prost-codec = ["prost", "bytes"] nightly = [] boringssl = ["grpcio-sys/boringssl", "_secure"] @@ -55,4 +57,4 @@ no-omit-frame-pointer = ["grpcio-sys/no-omit-frame-pointer"] travis-ci = { repository = "tikv/grpc-rs" } [patch.crates-io] -grpcio-compiler = { path = "compiler", version = "0.12.1", default-features = false } +grpcio-compiler = { path = "compiler", version = "0.13.0" } diff --git a/METADATA b/METADATA index 3129a8f..082d18a 100644 --- a/METADATA +++ b/METADATA @@ -1,3 +1,7 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/grpcio +# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md + name: "grpcio" description: "The rust language implementation of gRPC, base on the gRPC c core library." third_party { @@ -7,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/grpcio/grpcio-0.9.1.crate" + value: "https://static.crates.io/crates/grpcio/grpcio-0.13.0.crate" } - version: "0.12.1" + version: "0.13.0" license_type: NOTICE last_upgrade_date { year: 2023 - month: 6 - day: 21 + month: 10 + day: 26 } } diff --git a/README.md b/README.md index 7767c62..f027da4 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ This project is still under development. The following features with the check m - binutils >= 2.22 - LLVM and Clang >= 3.9 if you need to generate bindings at compile time. -For Linux and MacOS, you also need to install gcc 4.9+ (or clang) too. +For Linux and MacOS, you also need to install gcc 7.3+ (or clang 6+) too. Bindings are pre-generated for x86_64/arm64 Linux. For other platforms, bindings are generated at compile time. @@ -89,7 +89,7 @@ To include this project as a dependency: ``` [dependencies] -grpcio = "0.12" +grpcio = "0.13" ``` ### Feature `boringssl` @@ -99,7 +99,7 @@ mechanism. When you do not need it, for example when working in intranet, you can disable it by using the following configuration: ``` [dependencies] -grpcio = { version = "0.12", default-features = false, features = ["protobuf-codec"] } +grpcio = { version = "0.13", default-features = false, features = ["protobuf-codec"] } ``` ### Feature `prost-codec` and `protobuf-codec` @@ -119,7 +119,7 @@ your `Cargo.toml`'s features list for `gprcio`, which requires openssl (>=1.0.2) ```toml [dependencies] -grpcio = { version = "0.12", features = ["openssl"] } +grpcio = { version = "0.13", features = ["openssl"] } ``` Feature `openssl-vendored` is the same as feature `openssl` except it will build openssl from diff --git a/src/auth_context.rs b/src/auth_context.rs deleted file mode 100644 index 2658336..0000000 --- a/src/auth_context.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! API for authenticating peer -//! Based on https://grpc.github.io/grpc/core/md_doc_server_side_auth.html - -use std::ffi::CStr; -use std::marker::PhantomData; -use std::ptr::NonNull; - -use crate::grpc_sys::{ - self, grpc_auth_context, grpc_auth_property, grpc_auth_property_iterator, grpc_call, -}; - -/// To perform server-side authentication, gRPC exposes the authentication context -/// for each call. The context exposes important authentication-related information -/// about the RPC such as the type of security/authentication type being used and -/// the peer identity. -/// -/// The authentication context is structured as a multi-map of key-value pairs - -/// the auth properties. In addition to that, for authenticated RPCs, the set of -/// properties corresponding to a selected key will represent the verified identity -/// of the caller - the peer identity. -/// -/// The contents of the auth properties are populated by an auth interceptor within -/// gRPC Core. The interceptor also chooses which property key will act as the peer -/// identity (e.g. for client certificate authentication this property will be -/// `x509_common_name` or `x509_subject_alternative_name`). -pub struct AuthContext { - ctx: NonNull, -} - -/// Binding to gRPC Core AuthContext -impl AuthContext { - pub(crate) unsafe fn from_call_ptr(call: *mut grpc_call) -> Option { - NonNull::new(grpc_sys::grpc_call_auth_context(call)).map(|ctx| AuthContext { ctx }) - } - - /// The name of the property gRPC Core has chosen as main peer identity property, - /// if any. - pub fn peer_identity_property_name(&self) -> Option<&str> { - unsafe { - let p = grpc_sys::grpc_auth_context_peer_identity_property_name(self.ctx.as_ref()); - if p.is_null() { - None - } else { - Some(CStr::from_ptr(p).to_str().expect("valid UTF-8 data")) - } - } - } - - /// `true` if the client has provided a valid certificate (or other auth method - /// considered valid by gRPC). - /// `false` in non-secure scenarios. - pub fn peer_is_authenticated(&self) -> bool { - unsafe { grpc_sys::grpc_auth_context_peer_is_authenticated(self.ctx.as_ref()) != 0 } - } - - /// `AuthContext[peer_identity_property_name()]` - /// - /// There may be several of them (for instance if `x509_subject_alternative_name` is selected) - pub fn peer_identity(&self) -> AuthPropertyIter { - unsafe { - // grpc_auth_context_peer_identity returns empty_iterator when self.ctx is NULL - let iter = grpc_sys::grpc_auth_context_peer_identity(self.ctx.as_ref()); - AuthPropertyIter { - iter, - _lifetime: PhantomData, - } - } - } -} - -impl<'a> IntoIterator for &'a AuthContext { - type Item = AuthProperty<'a>; - type IntoIter = AuthPropertyIter<'a>; - - /// Iterate over the AuthContext properties - fn into_iter(self) -> Self::IntoIter { - unsafe { - // grpc_auth_context_property_iterator returns empty_iterator when self.ctx is NULL - let iter = grpc_sys::grpc_auth_context_property_iterator(self.ctx.as_ref()); - AuthPropertyIter { - iter, - _lifetime: PhantomData, - } - } - } -} - -impl Drop for AuthContext { - fn drop(&mut self) { - unsafe { grpc_sys::grpc_auth_context_release(self.ctx.as_ptr()) } - } -} - -pub struct AuthPropertyIter<'a> { - iter: grpc_auth_property_iterator, - _lifetime: PhantomData<&'a grpc_auth_property_iterator>, -} - -impl<'a> Iterator for AuthPropertyIter<'a> { - type Item = AuthProperty<'a>; - - fn next(&mut self) -> Option { - // grpc_auth_property_iterator_next returns empty_iterator when self.iter is NULL - let prop = unsafe { grpc_sys::grpc_auth_property_iterator_next(&mut self.iter) }; - if prop.is_null() { - None - } else { - Some(AuthProperty { - prop, - _lifetime: PhantomData, - }) - } - } -} - -/// Auth properties are elements of the AuthContext. They have a name -/// (a key of type string) and a value which can be a string or binary data. -pub struct AuthProperty<'a> { - prop: *const grpc_auth_property, - _lifetime: PhantomData<&'a grpc_auth_property>, -} - -impl<'a> AuthProperty<'a> { - pub fn name(&self) -> &'a str { - unsafe { CStr::from_ptr((*self.prop).name) } - .to_str() - .expect("Auth property name should be valid UTF-8 data") - } - - pub fn value(&self) -> &'a [u8] { - unsafe { - std::slice::from_raw_parts((*self.prop).value as *const u8, (*self.prop).value_length) - } - } - - pub fn value_str(&self) -> Result<&'a str, std::str::Utf8Error> { - std::str::from_utf8(self.value()) - } -} diff --git a/src/call/server.rs b/src/call/server.rs index 35149e0..ce3ca76 100644 --- a/src/call/server.rs +++ b/src/call/server.rs @@ -16,7 +16,6 @@ use futures_util::{Sink, Stream}; use parking_lot::Mutex; use super::{RpcStatus, ShareCall, ShareCallHolder, WriteFlags}; -use crate::auth_context::AuthContext; use crate::buf::GrpcSlice; use crate::call::{ BatchContext, Call, MessageReader, MethodType, RpcStatusCode, SinkBase, StreamingBase, @@ -193,10 +192,11 @@ impl RequestContext { } /// If the server binds in non-secure mode, this will return None - fn auth_context(&self) -> Option { + #[cfg(feature = "_secure")] + fn auth_context(&self) -> Option { unsafe { let call = grpc_sys::grpcwrap_request_call_context_get_call(self.ctx); - AuthContext::from_call_ptr(call) + crate::AuthContext::from_call_ptr(call) } } } @@ -690,7 +690,8 @@ impl<'a> RpcContext<'a> { /// Wrapper around the gRPC Core AuthContext /// /// If the server binds in non-secure mode, this will return None - pub fn auth_context(&self) -> Option { + #[cfg(feature = "_secure")] + pub fn auth_context(&self) -> Option { self.ctx.auth_context() } diff --git a/src/channel.rs b/src/channel.rs index 057b614..1ddf079 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -31,7 +31,7 @@ pub use crate::grpc_sys::{ /// Ref: http://www.grpc.io/docs/guides/wire.html#user-agents fn format_user_agent_string(agent: &str) -> CString { - let version = env!("CARGO_PKG_VERSION"); + let version = "0.13.0"; let trimed_agent = agent.trim(); let val = if trimed_agent.is_empty() { format!("grpc-rust/{version}") diff --git a/src/codec.rs b/src/codec.rs index e4449e6..c51a284 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -29,11 +29,15 @@ pub struct Marshaller { pub de: DeserializeFn, } -#[cfg(feature = "protobuf-codec")] +#[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] pub mod pb_codec { - use protobuf::{CodedInputStream, CodedOutputStream, Message}; + #[cfg(feature = "protobuf-codec")] + use protobuf::{CodedOutputStream, Message}; - use super::{MessageReader, MAX_MESSAGE_SIZE}; + #[cfg(feature = "protobufv3-codec")] + use protobufv3::{CodedOutputStream, Message}; + + use super::{from_buf_read, MessageReader, MAX_MESSAGE_SIZE}; use crate::buf::GrpcSlice; use crate::error::{Error, Result}; @@ -57,13 +61,23 @@ pub mod pb_codec { #[inline] pub fn de(mut reader: MessageReader) -> Result { - let mut s = CodedInputStream::from_buffered_reader(&mut reader); + let mut s = from_buf_read(&mut reader); let mut m = T::new(); m.merge_from(&mut s)?; Ok(m) } } +#[cfg(feature = "protobuf-codec")] +fn from_buf_read(reader: &mut MessageReader) -> protobuf::CodedInputStream { + protobuf::CodedInputStream::from_buffered_reader(reader) +} + +#[cfg(feature = "protobufv3-codec")] +fn from_buf_read(reader: &mut MessageReader) -> protobufv3::CodedInputStream { + protobufv3::CodedInputStream::from_buf_read(reader) +} + #[cfg(feature = "prost-codec")] pub mod pr_codec { use prost::Message; diff --git a/src/error.rs b/src/error.rs index 260425c..3b0dc74 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,6 +9,9 @@ use crate::grpc_sys::grpc_call_error; #[cfg(feature = "protobuf-codec")] use protobuf::ProtobufError; +#[cfg(feature = "protobufv3-codec")] +use protobufv3::Error as ProtobufError; + /// Errors generated from this library. #[derive(Debug)] pub enum Error { @@ -58,7 +61,7 @@ impl error::Error for Error { } } -#[cfg(feature = "protobuf-codec")] +#[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] impl From for Error { fn from(e: ProtobufError) -> Error { Error::Codec(Box::new(e)) diff --git a/src/lib.rs b/src/lib.rs index 0e5d225..c8cebca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,6 @@ use grpcio_sys as grpc_sys; #[macro_use] extern crate log; -mod auth_context; mod buf; mod call; mod channel; @@ -63,12 +62,11 @@ pub use crate::channel::{ }; pub use crate::client::Client; -#[cfg(feature = "protobuf-codec")] +#[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] pub use crate::codec::pb_codec::{de as pb_de, ser as pb_ser}; #[cfg(feature = "prost-codec")] pub use crate::codec::pr_codec::{de as pr_de, ser as pr_ser}; -pub use crate::auth_context::{AuthContext, AuthProperty, AuthPropertyIter}; pub use crate::codec::{Marshaller, MAX_MESSAGE_SIZE}; pub use crate::env::{EnvBuilder, Environment}; pub use crate::error::{Error, Result}; diff --git a/src/log_util.rs b/src/log_util.rs index 974f27a..0eddf83 100644 --- a/src/log_util.rs +++ b/src/log_util.rs @@ -30,9 +30,9 @@ extern "C" fn delegate(c_args: *mut gpr_log_func_args) { &Record::builder() .args(format_args!("{msg}")) .level(level) - .file(file_str.into()) + .file_static(file_str.into()) .line(line.into()) - .module_path(module_path!().into()) + .module_path_static(module_path!().into()) .build(), ); } diff --git a/src/metadata.rs b/src/metadata.rs index fc925de..3f940b0 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -19,11 +19,11 @@ fn normalize_key(key: &str, binary: bool) -> Result> { let mut is_upper_case = false; for b in key.as_bytes() { let b = *b; - if (b'A'..=b'Z').contains(&b) { + if b.is_ascii_uppercase() { is_upper_case = true; continue; - } else if (b'a'..=b'z').contains(&b) - || (b'0'..=b'9').contains(&b) + } else if b.is_ascii_lowercase() + || b.is_ascii_digit() || b == b'_' || b == b'-' || b == b'.' diff --git a/src/security/auth_context.rs b/src/security/auth_context.rs new file mode 100644 index 0000000..2658336 --- /dev/null +++ b/src/security/auth_context.rs @@ -0,0 +1,139 @@ +//! API for authenticating peer +//! Based on https://grpc.github.io/grpc/core/md_doc_server_side_auth.html + +use std::ffi::CStr; +use std::marker::PhantomData; +use std::ptr::NonNull; + +use crate::grpc_sys::{ + self, grpc_auth_context, grpc_auth_property, grpc_auth_property_iterator, grpc_call, +}; + +/// To perform server-side authentication, gRPC exposes the authentication context +/// for each call. The context exposes important authentication-related information +/// about the RPC such as the type of security/authentication type being used and +/// the peer identity. +/// +/// The authentication context is structured as a multi-map of key-value pairs - +/// the auth properties. In addition to that, for authenticated RPCs, the set of +/// properties corresponding to a selected key will represent the verified identity +/// of the caller - the peer identity. +/// +/// The contents of the auth properties are populated by an auth interceptor within +/// gRPC Core. The interceptor also chooses which property key will act as the peer +/// identity (e.g. for client certificate authentication this property will be +/// `x509_common_name` or `x509_subject_alternative_name`). +pub struct AuthContext { + ctx: NonNull, +} + +/// Binding to gRPC Core AuthContext +impl AuthContext { + pub(crate) unsafe fn from_call_ptr(call: *mut grpc_call) -> Option { + NonNull::new(grpc_sys::grpc_call_auth_context(call)).map(|ctx| AuthContext { ctx }) + } + + /// The name of the property gRPC Core has chosen as main peer identity property, + /// if any. + pub fn peer_identity_property_name(&self) -> Option<&str> { + unsafe { + let p = grpc_sys::grpc_auth_context_peer_identity_property_name(self.ctx.as_ref()); + if p.is_null() { + None + } else { + Some(CStr::from_ptr(p).to_str().expect("valid UTF-8 data")) + } + } + } + + /// `true` if the client has provided a valid certificate (or other auth method + /// considered valid by gRPC). + /// `false` in non-secure scenarios. + pub fn peer_is_authenticated(&self) -> bool { + unsafe { grpc_sys::grpc_auth_context_peer_is_authenticated(self.ctx.as_ref()) != 0 } + } + + /// `AuthContext[peer_identity_property_name()]` + /// + /// There may be several of them (for instance if `x509_subject_alternative_name` is selected) + pub fn peer_identity(&self) -> AuthPropertyIter { + unsafe { + // grpc_auth_context_peer_identity returns empty_iterator when self.ctx is NULL + let iter = grpc_sys::grpc_auth_context_peer_identity(self.ctx.as_ref()); + AuthPropertyIter { + iter, + _lifetime: PhantomData, + } + } + } +} + +impl<'a> IntoIterator for &'a AuthContext { + type Item = AuthProperty<'a>; + type IntoIter = AuthPropertyIter<'a>; + + /// Iterate over the AuthContext properties + fn into_iter(self) -> Self::IntoIter { + unsafe { + // grpc_auth_context_property_iterator returns empty_iterator when self.ctx is NULL + let iter = grpc_sys::grpc_auth_context_property_iterator(self.ctx.as_ref()); + AuthPropertyIter { + iter, + _lifetime: PhantomData, + } + } + } +} + +impl Drop for AuthContext { + fn drop(&mut self) { + unsafe { grpc_sys::grpc_auth_context_release(self.ctx.as_ptr()) } + } +} + +pub struct AuthPropertyIter<'a> { + iter: grpc_auth_property_iterator, + _lifetime: PhantomData<&'a grpc_auth_property_iterator>, +} + +impl<'a> Iterator for AuthPropertyIter<'a> { + type Item = AuthProperty<'a>; + + fn next(&mut self) -> Option { + // grpc_auth_property_iterator_next returns empty_iterator when self.iter is NULL + let prop = unsafe { grpc_sys::grpc_auth_property_iterator_next(&mut self.iter) }; + if prop.is_null() { + None + } else { + Some(AuthProperty { + prop, + _lifetime: PhantomData, + }) + } + } +} + +/// Auth properties are elements of the AuthContext. They have a name +/// (a key of type string) and a value which can be a string or binary data. +pub struct AuthProperty<'a> { + prop: *const grpc_auth_property, + _lifetime: PhantomData<&'a grpc_auth_property>, +} + +impl<'a> AuthProperty<'a> { + pub fn name(&self) -> &'a str { + unsafe { CStr::from_ptr((*self.prop).name) } + .to_str() + .expect("Auth property name should be valid UTF-8 data") + } + + pub fn value(&self) -> &'a [u8] { + unsafe { + std::slice::from_raw_parts((*self.prop).value as *const u8, (*self.prop).value_length) + } + } + + pub fn value_str(&self) -> Result<&'a str, std::str::Utf8Error> { + std::str::from_utf8(self.value()) + } +} diff --git a/src/security/mod.rs b/src/security/mod.rs index c935461..d0fa76c 100644 --- a/src/security/mod.rs +++ b/src/security/mod.rs @@ -1,10 +1,14 @@ // Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. +#[cfg(feature = "_secure")] +mod auth_context; #[cfg(feature = "_secure")] mod credentials; use grpcio_sys::{grpc_channel_credentials, grpc_server_credentials}; +#[cfg(feature = "_secure")] +pub use self::auth_context::*; #[cfg(feature = "_secure")] pub use self::credentials::{ CertificateRequestType, ChannelCredentialsBuilder, ServerCredentialsBuilder, @@ -59,6 +63,7 @@ impl ServerCredentials { ServerCredentials::from_raw(creds) } } + pub(crate) unsafe fn from_raw(creds: *mut grpc_server_credentials) -> ServerCredentials { ServerCredentials { creds, -- cgit v1.2.3