Skip to content

Commit 7d6683e

Browse files
authored
Write grpc-web trailer names to response as lowercase (#1170)
1 parent ab2efba commit 7d6683e

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

examples/Browser/Server/wwwroot/Scripts/index.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,15 @@ streamInput.onclick = function () {
3030
request.setName(nameInput.value);
3131

3232
streamingCall = client.sayHellos(request, {});
33-
streamingCall.on('data', function (response) {
33+
streamingCall.on('data', (response) => {
3434
resultText.innerHTML += htmlEscape(response.getMessage()) + '<br />';
3535
});
36-
streamingCall.on('end', function () {
36+
streamingCall.on('status', (status) => {
37+
if (status.code == 0) {
38+
resultText.innerHTML += 'Done';
39+
} else {
40+
resultText.innerHTML += 'Error: ' + htmlEscape(status.details);
41+
}
3742
});
3843
} else {
3944
streamingCall.cancel();

src/Grpc.AspNetCore.Web/Internal/GrpcWebProtocolHelpers.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,17 @@ private static void WriteTrailersContent(Span<byte> buffer, IHeaderDictionary tr
117117
{
118118
if (value != null)
119119
{
120-
var position = Encoding.ASCII.GetBytes(kv.Key, currentBuffer);
120+
// Get lower-case ASCII bytes for the key.
121+
// gRPC-Web protocol says that names should be lower-case and grpc-web JS client
122+
// will check for 'grpc-status' and 'grpc-message' in trailers with lower-case key.
123+
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2
124+
for (int i = 0; i < kv.Key.Length; i++)
125+
{
126+
char c = kv.Key[i];
127+
currentBuffer[i] = (byte)((uint)(c - 'A') <= ('Z' - 'A') ? c | 0x20 : c);
128+
}
129+
130+
var position = kv.Key.Length;
121131

122132
currentBuffer[position++] = Colon;
123133
currentBuffer[position++] = Space;

test/Grpc.AspNetCore.Server.Tests/Web/GrpcWebProtocolHelpersTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,31 @@ public void WriteTrailers_OneTrailer_WrittenToOutput()
7474
Assert.AreEqual("one: two\r\n", text);
7575
}
7676

77+
[Test]
78+
public void WriteTrailers_OneTrailerMixedCase_WrittenToOutputLowerCase()
79+
{
80+
// Arrange
81+
var trailers = new HeaderDictionary();
82+
trailers.Add("One", "Two");
83+
var output = new ArrayBufferWriter<byte>();
84+
85+
// Act
86+
GrpcWebProtocolHelpers.WriteTrailers(trailers, output);
87+
88+
// Assert
89+
Assert.AreEqual(15, output.WrittenSpan.Length);
90+
91+
Assert.AreEqual(128, output.WrittenSpan[0]);
92+
Assert.AreEqual(0, output.WrittenSpan[1]);
93+
Assert.AreEqual(0, output.WrittenSpan[2]);
94+
Assert.AreEqual(0, output.WrittenSpan[3]);
95+
Assert.AreEqual(10, output.WrittenSpan[4]);
96+
97+
var text = Encoding.ASCII.GetString(output.WrittenSpan.Slice(5));
98+
99+
Assert.AreEqual("one: Two\r\n", text);
100+
}
101+
77102
[Test]
78103
public void WriteTrailers_MultiValueTrailer_WrittenToOutput()
79104
{

0 commit comments

Comments
 (0)