/** * Called by transport implementations when they receive headers. * * @param headers the parsed headers */ protected void inboundHeadersReceived(Metadata headers) { if (headers.containsKey(GrpcUtil.MESSAGE_ENCODING_KEY)) { String messageEncoding = headers.get(GrpcUtil.MESSAGE_ENCODING_KEY); try { setDecompressor(messageEncoding); } catch (IllegalArgumentException e) { Status status = Status.INVALID_ARGUMENT .withDescription("Unable to decompress encoding " + messageEncoding) .withCause(e); abortStream(status, true); return; } } // This checks to see if the client will accept any encoding. If so, a compressor is picked for // the stream, and the decision is recorded. When the Server Call Handler writes the first // headers, the negotiated encoding will be added in #writeHeaders(). It is safe to call // pickCompressor multiple times before the headers have been written to the wire, though in // practice this should never happen. There should only be one call to inboundHeadersReceived. // Alternatively, compression could be negotiated after the server handler is invoked, but that // would mean the inbound header would have to be stored until the first #writeHeaders call. if (headers.containsKey(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY)) { Compressor c = pickCompressor( ACCEPT_ENCODING_SPLITER.split(headers.get(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY))); if (c != null) { messageEncoding = c.getMessageEncoding(); } } inboundPhase(Phase.MESSAGE); }
@VisibleForTesting static void prepareHeaders( Metadata headers, CallOptions callOptions, String userAgent, DecompressorRegistry decompressorRegistry, Compressor compressor) { // Fill out the User-Agent header. headers.removeAll(USER_AGENT_KEY); if (userAgent != null) { headers.put(USER_AGENT_KEY, userAgent); } headers.removeAll(MESSAGE_ENCODING_KEY); if (compressor != Codec.Identity.NONE) { headers.put(MESSAGE_ENCODING_KEY, compressor.getMessageEncoding()); } headers.removeAll(MESSAGE_ACCEPT_ENCODING_KEY); if (!decompressorRegistry.getAdvertisedMessageEncodings().isEmpty()) { String acceptEncoding = ACCEPT_ENCODING_JOINER.join(decompressorRegistry.getAdvertisedMessageEncodings()); headers.put(MESSAGE_ACCEPT_ENCODING_KEY, acceptEncoding); } }
private void writeCompressed(InputStream message) throws IOException { BufferChainOutputStream bufferChain = new BufferChainOutputStream(); // Why this doesn't use getKnownLength() idk, but let's just roll with it. int messageLength = -1; if (message instanceof KnownLength) { messageLength = message.available(); } OutputStream compressingStream = compressor.compress(bufferChain); try { long written = writeToOutputStream(message, compressingStream); if (messageLength != -1 && messageLength != written) { throw new RuntimeException("Message length was inaccurate"); } } finally { compressingStream.close(); } writeBufferChain(bufferChain, true); }