/**
   * 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);
  }
Example #2
0
  @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);
    }
  }
Example #3
0
  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);
  }