From 5909eceef55460b6ffd50e94513e9cf8d4c39f92 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 12 Jan 2021 15:02:45 +1300 Subject: [PATCH 1/3] Write grpc-web trailer names in lowercase --- .../Internal/GrpcWebProtocolHelpers.cs | 12 ++++++++- .../Web/GrpcWebProtocolHelpersTests.cs | 25 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/Grpc.AspNetCore.Web/Internal/GrpcWebProtocolHelpers.cs b/src/Grpc.AspNetCore.Web/Internal/GrpcWebProtocolHelpers.cs index 891173fe4..1950c5469 100644 --- a/src/Grpc.AspNetCore.Web/Internal/GrpcWebProtocolHelpers.cs +++ b/src/Grpc.AspNetCore.Web/Internal/GrpcWebProtocolHelpers.cs @@ -117,7 +117,17 @@ private static void WriteTrailersContent(Span buffer, IHeaderDictionary tr { if (value != null) { - var position = Encoding.ASCII.GetBytes(kv.Key, currentBuffer); + // Get lower-case ASCII bytes for the key. + // gRPC-Web protocol says that names should be lower-case and grpc-web JS client + // will check for 'grpc-status' and 'grpc-message' in trailers with lower-case key. + // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2 + for (int i = 0; i < kv.Key.Length; i++) + { + char c = kv.Key[i]; + currentBuffer[i] = (byte)((uint)(c - 'A') <= ('Z' - 'A') ? c | 0x20 : c); + } + + var position = kv.Key.Length; currentBuffer[position++] = Colon; currentBuffer[position++] = Space; diff --git a/test/Grpc.AspNetCore.Server.Tests/Web/GrpcWebProtocolHelpersTests.cs b/test/Grpc.AspNetCore.Server.Tests/Web/GrpcWebProtocolHelpersTests.cs index b54de173f..5cb5ab455 100644 --- a/test/Grpc.AspNetCore.Server.Tests/Web/GrpcWebProtocolHelpersTests.cs +++ b/test/Grpc.AspNetCore.Server.Tests/Web/GrpcWebProtocolHelpersTests.cs @@ -74,6 +74,31 @@ public void WriteTrailers_OneTrailer_WrittenToOutput() Assert.AreEqual("one: two\r\n", text); } + [Test] + public void WriteTrailers_OneTrailerMixedCase_WrittenToOutputLowerCase() + { + // Arrange + var trailers = new HeaderDictionary(); + trailers.Add("One", "two"); + var output = new ArrayBufferWriter(); + + // Act + GrpcWebProtocolHelpers.WriteTrailers(trailers, output); + + // Assert + Assert.AreEqual(15, output.WrittenSpan.Length); + + Assert.AreEqual(128, output.WrittenSpan[0]); + Assert.AreEqual(0, output.WrittenSpan[1]); + Assert.AreEqual(0, output.WrittenSpan[2]); + Assert.AreEqual(0, output.WrittenSpan[3]); + Assert.AreEqual(10, output.WrittenSpan[4]); + + var text = Encoding.ASCII.GetString(output.WrittenSpan.Slice(5)); + + Assert.AreEqual("one: two\r\n", text); + } + [Test] public void WriteTrailers_MultiValueTrailer_WrittenToOutput() { From cb1d203145f0742f5673d990608f2c137c66ded5 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 12 Jan 2021 15:04:32 +1300 Subject: [PATCH 2/3] Update --- .../Web/GrpcWebProtocolHelpersTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Grpc.AspNetCore.Server.Tests/Web/GrpcWebProtocolHelpersTests.cs b/test/Grpc.AspNetCore.Server.Tests/Web/GrpcWebProtocolHelpersTests.cs index 5cb5ab455..49e4d94dc 100644 --- a/test/Grpc.AspNetCore.Server.Tests/Web/GrpcWebProtocolHelpersTests.cs +++ b/test/Grpc.AspNetCore.Server.Tests/Web/GrpcWebProtocolHelpersTests.cs @@ -79,7 +79,7 @@ public void WriteTrailers_OneTrailerMixedCase_WrittenToOutputLowerCase() { // Arrange var trailers = new HeaderDictionary(); - trailers.Add("One", "two"); + trailers.Add("One", "Two"); var output = new ArrayBufferWriter(); // Act @@ -96,7 +96,7 @@ public void WriteTrailers_OneTrailerMixedCase_WrittenToOutputLowerCase() var text = Encoding.ASCII.GetString(output.WrittenSpan.Slice(5)); - Assert.AreEqual("one: two\r\n", text); + Assert.AreEqual("one: Two\r\n", text); } [Test] From a0d642e63e1d7130b1dc869c62f70fc781bbd0e4 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 12 Jan 2021 16:01:36 +1300 Subject: [PATCH 3/3] Update grpc-web sample --- examples/Browser/Server/wwwroot/Scripts/index.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/Browser/Server/wwwroot/Scripts/index.js b/examples/Browser/Server/wwwroot/Scripts/index.js index 8d2969366..68ab01099 100644 --- a/examples/Browser/Server/wwwroot/Scripts/index.js +++ b/examples/Browser/Server/wwwroot/Scripts/index.js @@ -30,10 +30,15 @@ streamInput.onclick = function () { request.setName(nameInput.value); streamingCall = client.sayHellos(request, {}); - streamingCall.on('data', function (response) { + streamingCall.on('data', (response) => { resultText.innerHTML += htmlEscape(response.getMessage()) + '
'; }); - streamingCall.on('end', function () { + streamingCall.on('status', (status) => { + if (status.code == 0) { + resultText.innerHTML += 'Done'; + } else { + resultText.innerHTML += 'Error: ' + htmlEscape(status.details); + } }); } else { streamingCall.cancel();