1# Copyright 2015 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15require 'spec_helper' 16 17TEST_DEBUG_MESSAGE = 'raised by test server'.freeze 18 19# a test service that checks the cert of its peer 20class DebugMessageTestService 21 include GRPC::GenericService 22 rpc :an_rpc_raises_abort, EchoMsg, EchoMsg 23 rpc :an_rpc_raises_standarderror, EchoMsg, EchoMsg 24 25 def an_rpc_raises_abort(_req, _call) 26 fail GRPC::Aborted.new( 27 'aborted', 28 {}, 29 TEST_DEBUG_MESSAGE) 30 end 31 32 def an_rpc_raises_standarderror(_req, _call) 33 fail(StandardError, TEST_DEBUG_MESSAGE) 34 end 35end 36 37DebugMessageTestServiceStub = DebugMessageTestService.rpc_stub_class 38 39describe 'surfacing and transmitting of debug messages' do 40 RpcServer = GRPC::RpcServer 41 42 before(:all) do 43 server_opts = { 44 poll_period: 1 45 } 46 @srv = new_rpc_server_for_testing(**server_opts) 47 @port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure) 48 @srv.handle(DebugMessageTestService) 49 @srv_thd = Thread.new { @srv.run } 50 @srv.wait_till_running 51 end 52 53 after(:all) do 54 expect(@srv.stopped?).to be(false) 55 @srv.stop 56 @srv_thd.join 57 end 58 59 it 'debug error message is not present BadStatus exceptions that dont set it' do 60 exception_message = '' 61 begin 62 fail GRPC::Unavailable('unavailable', {}) 63 rescue StandardError => e 64 p "Got exception: #{e.message}" 65 exception_message = e.message 66 end 67 expect(exception_message.empty?).to be(false) 68 expect(exception_message.include?('debug_error_string')).to be(false) 69 end 70 71 it 'debug error message is present in locally generated errors' do 72 # Create a secure channel. This is just one way to force a 73 # connection handshake error, which shoud result in C-core 74 # generating a status and error message and surfacing them up. 75 test_root = File.join(File.dirname(__FILE__), 'testdata') 76 files = ['ca.pem', 'client.key', 'client.pem'] 77 creds = files.map { |f| File.open(File.join(test_root, f)).read } 78 creds = GRPC::Core::ChannelCredentials.new(creds[0], creds[1], creds[2]) 79 stub = DebugMessageTestServiceStub.new( 80 "localhost:#{@port}", creds) 81 begin 82 stub.an_rpc_raises_abort(EchoMsg.new) 83 rescue StandardError => e 84 p "Got exception: #{e.message}" 85 exception_message = e.message 86 # check that the RPC did actually result in a BadStatus exception 87 expect(e.is_a?(GRPC::BadStatus)).to be(true) 88 end 89 # just check that the debug_error_string is non-empty (we know that 90 # it's a JSON object, so the first character is '{'). 91 expect(exception_message.include?('. debug_error_string:{')).to be(true) 92 end 93 94 it 'debug message is not transmitted from server to client' do 95 # in order to not accidentally leak internal details about a 96 # server to untrusted clients, avoid including the debug_error_string 97 # field of a BadStatusException raised at a server in the 98 # RPC status that it sends to clients. 99 stub = DebugMessageTestServiceStub.new( 100 "localhost:#{@port}", :this_channel_is_insecure) 101 exception_message = '' 102 begin 103 stub.an_rpc_raises_abort(EchoMsg.new) 104 rescue StandardError => e 105 p "Got exception: #{e.message}" 106 exception_message = e.message 107 # check that the status was aborted is an indirect way to 108 # tell that the RPC did actually get handled by the server 109 expect(e.is_a?(GRPC::Aborted)).to be(true) 110 end 111 # just assert that the contents of the server-side BadStatus 112 # debug_error_string field were *not* propagated to the client. 113 expect(exception_message.include?('. debug_error_string:{')).to be(true) 114 expect(exception_message.include?(TEST_DEBUG_MESSAGE)).to be(false) 115 end 116 117 it 'standard_error messages are transmitted from server to client' do 118 # this test exists mostly in order to understand the test case 119 # above, by comparison. 120 stub = DebugMessageTestServiceStub.new( 121 "localhost:#{@port}", :this_channel_is_insecure) 122 exception_message = '' 123 begin 124 stub.an_rpc_raises_standarderror(EchoMsg.new) 125 rescue StandardError => e 126 p "Got exception: #{e.message}" 127 exception_message = e.message 128 expect(e.is_a?(GRPC::BadStatus)).to be(true) 129 end 130 # assert that the contents of the StandardError exception message 131 # are propagated to the client. 132 expect(exception_message.include?(TEST_DEBUG_MESSAGE)).to be(true) 133 end 134end 135