Skip to content

Commit 43a9fa2

Browse files
committed
minor code cleanup; fix bug: grpc response w/ no trailers should result in error
1 parent 77ae245 commit 43a9fa2

File tree

4 files changed

+45
-35
lines changed

4 files changed

+45
-35
lines changed

library/src/main/kotlin/com/connectrpc/compression/CompressionPool.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ interface CompressionPool {
3737

3838
/**
3939
* Compress an outbound request message.
40-
* @param buffer: The uncompressed request message.
40+
* @param input: The uncompressed request message.
4141
* @return The compressed request message.
4242
*/
43-
fun compress(buffer: Buffer): Buffer
43+
fun compress(input: Buffer): Buffer
4444

4545
/**
4646
* Decompress an inbound response message.
47-
* @param buffer: The compressed response message.
47+
* @param input: The compressed response message.
4848
* @return The uncompressed response message.
4949
*/
50-
fun decompress(buffer: Buffer): Buffer
50+
fun decompress(input: Buffer): Buffer
5151
}

library/src/main/kotlin/com/connectrpc/compression/GzipCompressionPool.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,23 @@ object GzipCompressionPool : CompressionPool {
2828
return "gzip"
2929
}
3030

31-
override fun compress(buffer: Buffer): Buffer {
32-
val gzippedSink = Buffer()
33-
GzipSink(gzippedSink).use { source ->
34-
source.write(buffer, buffer.size)
31+
override fun compress(input: Buffer): Buffer {
32+
val result = Buffer()
33+
GzipSink(result).use { gzippedSink ->
34+
gzippedSink.write(input, input.size)
3535
}
36-
return gzippedSink
36+
return result
3737
}
3838

39-
override fun decompress(buffer: Buffer): Buffer {
39+
override fun decompress(input: Buffer): Buffer {
4040
val result = Buffer()
41-
if (buffer.size == 0L) return result
41+
// We're lenient and will allow an empty payload to be
42+
// interpreted as a compressed empty payload (even though
43+
// it's missing the gzip format preamble/metadata).
44+
if (input.size == 0L) return result
4245

43-
GzipSource(buffer).use {
44-
while (it.read(result, Int.MAX_VALUE.toLong()) != -1L) {
46+
GzipSource(input).use { gzippedSource ->
47+
while (gzippedSource.read(result, Int.MAX_VALUE.toLong()) != -1L) {
4548
// continue reading.
4649
}
4750
}

library/src/main/kotlin/com/connectrpc/protocols/Envelope.kt

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,23 @@ class Envelope {
3030
* @param compressionMinBytes The minimum bytes the source needs to be in order to be compressed.
3131
*/
3232
fun pack(source: Buffer, compressionPool: CompressionPool? = null, compressionMinBytes: Int? = null): Buffer {
33+
val flags: Int
34+
val payload: Buffer
3335
if (compressionMinBytes == null ||
3436
source.size < compressionMinBytes ||
3537
compressionPool == null
3638
) {
37-
return source.use {
38-
val result = Buffer()
39-
result.writeByte(0)
40-
result.writeInt(source.buffer.size.toInt())
41-
result.writeAll(source)
42-
result
43-
}
44-
}
45-
return source.use { buffer ->
46-
val result = Buffer()
47-
result.writeByte(1)
48-
val compressedBuffer = compressionPool.compress(buffer)
49-
result.writeInt(compressedBuffer.size.toInt())
50-
result.writeAll(compressedBuffer)
51-
result
39+
flags = 0
40+
payload = source
41+
} else {
42+
flags = 1
43+
payload = compressionPool.compress(source)
5244
}
45+
val result = Buffer()
46+
result.writeByte(flags)
47+
result.writeInt(payload.buffer.size.toInt())
48+
result.writeAll(payload)
49+
return result
5350
}
5451

5552
/**

library/src/main/kotlin/com/connectrpc/protocols/GRPCInterceptor.kt

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,29 @@ internal class GRPCInterceptor(
157157
onCompletion = { result ->
158158
val trailers = result.trailers
159159
val completion = completionParser.parse(emptyMap(), trailers)
160+
if (completion == null && result.cause != null) {
161+
// let error result propagate
162+
return@fold result
163+
}
164+
val exception: ConnectException?
160165
if (completion != null) {
161-
val exception = completion.toConnectExceptionOrNull(
166+
exception = completion.toConnectExceptionOrNull(
162167
serializationStrategy,
163168
result.cause,
164169
)
165-
StreamResult.Complete(
166-
code = exception?.code ?: Code.OK,
167-
cause = exception,
168-
trailers = trailers,
169-
)
170170
} else {
171-
result
171+
exception = ConnectException(
172+
code = Code.INTERNAL_ERROR,
173+
errorDetailParser = serializationStrategy.errorDetailParser(),
174+
message = "protocol error: status is missing from trailers",
175+
metadata = trailers,
176+
)
172177
}
178+
StreamResult.Complete(
179+
code = exception?.code ?: Code.OK,
180+
cause = exception,
181+
trailers = trailers,
182+
)
173183
},
174184
)
175185
},

0 commit comments

Comments
 (0)