예제 #1
0
  @Test
  public void contextDeadlineShouldNotOverrideSmallerMetadataTimeout() {
    long deadlineNanos = TimeUnit.SECONDS.toNanos(2);
    Context context =
        Context.current()
            .withDeadlineAfter(deadlineNanos, TimeUnit.NANOSECONDS, deadlineCancellationExecutor);
    context.attach();

    CallOptions callOpts = CallOptions.DEFAULT.withDeadlineAfter(1, TimeUnit.SECONDS);
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
            DESCRIPTOR,
            MoreExecutors.directExecutor(),
            callOpts,
            provider,
            deadlineCancellationExecutor);

    Metadata headers = new Metadata();

    call.start(callListener, headers);

    assertTrue(headers.containsKey(GrpcUtil.TIMEOUT_KEY));
    Long timeout = headers.get(GrpcUtil.TIMEOUT_KEY);
    assertNotNull(timeout);

    long callOptsNanos = TimeUnit.SECONDS.toNanos(1);
    long deltaNanos = TimeUnit.MILLISECONDS.toNanos(400);
    assertTimeoutBetween(timeout, callOptsNanos - deltaNanos, callOptsNanos);
  }
  /**
   * 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);
  }
예제 #3
0
  @Test
  public void prepareHeaders_ignoreIdentityEncoding() {
    Metadata m = new Metadata();
    ClientCallImpl.prepareHeaders(m, decompressorRegistry, Codec.Identity.NONE);

    assertNull(m.get(GrpcUtil.MESSAGE_ENCODING_KEY));
  }
예제 #4
0
    @Override
    public void headersRead(final Metadata headers) {
      Decompressor decompressor = Codec.Identity.NONE;
      if (headers.containsKey(MESSAGE_ENCODING_KEY)) {
        String encoding = headers.get(MESSAGE_ENCODING_KEY);
        decompressor = decompressorRegistry.lookupDecompressor(encoding);
        if (decompressor == null) {
          stream.cancel(
              Status.INTERNAL.withDescription(
                  String.format("Can't find decompressor for %s", encoding)));
          return;
        }
      }
      stream.setDecompressor(decompressor);

      callExecutor.execute(
          new ContextRunnable(context) {
            @Override
            public final void runInContext() {
              try {
                if (closed) {
                  return;
                }

                observer.onHeaders(headers);
              } catch (Throwable t) {
                stream.cancel(
                    Status.CANCELLED.withCause(t).withDescription("Failed to read headers"));
                return;
              }
            }
          });
    }
 /** Creates a {@link Metadata} that contains pertinent headers. */
 private Metadata createMetadata(String tableName) {
   Metadata metadata = new Metadata();
   if (tableName != null) {
     metadata.put(GRPC_RESOURCE_PREFIX_KEY, tableName);
   }
   return metadata;
 }
예제 #6
0
  @Test
  public void prepareHeaders_userAgentAdded() {
    Metadata m = new Metadata();
    ClientCallImpl.prepareHeaders(
        m, CallOptions.DEFAULT, "user agent", DecompressorRegistry.getDefaultInstance());

    assertEquals(m.get(GrpcUtil.USER_AGENT_KEY), "user agent");
  }
 private void writeStatusToTrailers(Status status) {
   stashedTrailers.removeAll(Status.CODE_KEY);
   stashedTrailers.removeAll(Status.MESSAGE_KEY);
   stashedTrailers.put(Status.CODE_KEY, status);
   if (status.getDescription() != null) {
     stashedTrailers.put(Status.MESSAGE_KEY, status.getDescription());
   }
 }
예제 #8
0
  @Test
  public void prepareHeaders_authorityAdded() {
    Metadata m = new Metadata();
    CallOptions callOptions = CallOptions.DEFAULT.withAuthority("auth");
    ClientCallImpl.prepareHeaders(
        m, callOptions, "user agent", DecompressorRegistry.getDefaultInstance());

    assertEquals(m.get(GrpcUtil.AUTHORITY_KEY), "auth");
  }
예제 #9
0
  @Test
  public void prepareHeaders_ignoreIdentityEncoding() {
    Metadata m = new Metadata();
    CallOptions callOptions = CallOptions.DEFAULT.withCompressor(Codec.Identity.NONE);
    ClientCallImpl.prepareHeaders(
        m, callOptions, "user agent", DecompressorRegistry.getDefaultInstance());

    assertNull(m.get(GrpcUtil.MESSAGE_ENCODING_KEY));
  }
예제 #10
0
  @Test
  public void prepareHeaders_userAgentIgnored() {
    Metadata m = new Metadata();
    m.put(GrpcUtil.USER_AGENT_KEY, "batmobile");
    ClientCallImpl.prepareHeaders(m, decompressorRegistry, Codec.Identity.NONE);

    // User Agent is removed and set by the transport
    assertThat(m.get(GrpcUtil.USER_AGENT_KEY)).isNotNull();
  }
예제 #11
0
  @Test
  public void prepareHeaders_messageEncodingAdded() {
    Metadata m = new Metadata();
    CallOptions callOptions = CallOptions.DEFAULT.withCompressor(new Codec.Gzip());
    ClientCallImpl.prepareHeaders(
        m, callOptions, "user agent", DecompressorRegistry.getDefaultInstance());

    assertEquals(m.get(GrpcUtil.MESSAGE_ENCODING_KEY), new Codec.Gzip().getMessageEncoding());
  }
예제 #12
0
  @Test
  public void prepareHeaders_removeReservedHeaders() {
    Metadata m = new Metadata();
    m.put(GrpcUtil.MESSAGE_ENCODING_KEY, "gzip");
    m.put(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY, "gzip");

    ClientCallImpl.prepareHeaders(m, DecompressorRegistry.emptyInstance(), Codec.Identity.NONE);

    assertNull(m.get(GrpcUtil.MESSAGE_ENCODING_KEY));
    assertNull(m.get(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));
  }
예제 #13
0
  @Test
  public void prepareHeaders_acceptedEncodingsAdded() {
    Metadata m = new Metadata();
    DecompressorRegistry customRegistry =
        DecompressorRegistry.emptyInstance()
            .with(
                new Decompressor() {
                  @Override
                  public String getMessageEncoding() {
                    return "a";
                  }

                  @Override
                  public InputStream decompress(InputStream is) throws IOException {
                    return null;
                  }
                },
                true)
            .with(
                new Decompressor() {
                  @Override
                  public String getMessageEncoding() {
                    return "b";
                  }

                  @Override
                  public InputStream decompress(InputStream is) throws IOException {
                    return null;
                  }
                },
                true)
            .with(
                new Decompressor() {
                  @Override
                  public String getMessageEncoding() {
                    return "c";
                  }

                  @Override
                  public InputStream decompress(InputStream is) throws IOException {
                    return null;
                  }
                },
                false); // not advertised

    ClientCallImpl.prepareHeaders(m, customRegistry, Codec.Identity.NONE);

    Iterable<String> acceptedEncodings =
        ACCEPT_ENCODING_SPLITER.split(m.get(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));

    // Order may be different, since decoder priorities have not yet been implemented.
    assertEquals(ImmutableSet.of("b", "a"), ImmutableSet.copyOf(acceptedEncodings));
  }
예제 #14
0
  /** Without a context or call options deadline, a timeout should not be set in metadata. */
  @Test
  public void timeoutShouldNotBeSet() {
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
            DESCRIPTOR,
            MoreExecutors.directExecutor(),
            CallOptions.DEFAULT,
            provider,
            deadlineCancellationExecutor);

    Metadata headers = new Metadata();

    call.start(callListener, headers);

    assertFalse(headers.containsKey(GrpcUtil.TIMEOUT_KEY));
  }
예제 #15
0
  /** Based on the deadline, calculate and set the timeout to the given headers. */
  private static void updateTimeoutHeaders(
      @Nullable Deadline effectiveDeadline,
      @Nullable Deadline callDeadline,
      @Nullable Deadline outerCallDeadline,
      Metadata headers) {
    headers.removeAll(TIMEOUT_KEY);

    if (effectiveDeadline == null) {
      return;
    }

    long effectiveTimeout = max(0, effectiveDeadline.timeRemaining(TimeUnit.NANOSECONDS));
    headers.put(TIMEOUT_KEY, effectiveTimeout);

    logIfContextNarrowedTimeout(
        effectiveTimeout, effectiveDeadline, outerCallDeadline, callDeadline);
  }
예제 #16
0
  @Override
  public final void writeHeaders(Metadata headers) {
    Preconditions.checkNotNull(headers, "headers");
    headers.removeAll(MESSAGE_ENCODING_KEY);
    if (messageEncoding != null) {
      headers.put(MESSAGE_ENCODING_KEY, messageEncoding);
    }
    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);
    }

    outboundPhase(Phase.HEADERS);
    headersSent = true;
    internalSendHeaders(headers);
    outboundPhase(Phase.MESSAGE);
  }
예제 #17
0
  @Test
  public void advertisedEncodingsAreSent() {
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
                method,
                MoreExecutors.directExecutor(),
                CallOptions.DEFAULT,
                provider,
                deadlineCancellationExecutor)
            .setDecompressorRegistry(decompressorRegistry);

    call.start(callListener, new Metadata());

    ArgumentCaptor<Metadata> metadataCaptor = ArgumentCaptor.forClass(Metadata.class);
    verify(transport).newStream(eq(method), metadataCaptor.capture(), same(CallOptions.DEFAULT));
    Metadata actual = metadataCaptor.getValue();

    Set<String> acceptedEncodings =
        ImmutableSet.copyOf(actual.getAll(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));
    assertEquals(decompressorRegistry.getAdvertisedMessageEncodings(), acceptedEncodings);
  }
예제 #18
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);
    }
  }
예제 #19
0
  @Test
  public void prepareHeaders_removeReservedHeaders() {
    Metadata m = new Metadata();
    m.put(GrpcUtil.AUTHORITY_KEY, "auth");
    m.put(GrpcUtil.USER_AGENT_KEY, "user agent");
    m.put(GrpcUtil.MESSAGE_ENCODING_KEY, "gzip");
    m.put(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY, "gzip");

    ClientCallImpl.prepareHeaders(
        m, CallOptions.DEFAULT, null, DecompressorRegistry.newEmptyInstance());

    assertNull(m.get(GrpcUtil.AUTHORITY_KEY));
    assertNull(m.get(GrpcUtil.USER_AGENT_KEY));
    assertNull(m.get(GrpcUtil.MESSAGE_ENCODING_KEY));
    assertNull(m.get(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));
  }
예제 #20
0
  @Test
  public void advertisedEncodingsAreSent() {
    MethodDescriptor<Void, Void> descriptor =
        MethodDescriptor.create(
            MethodType.UNARY,
            "service/method",
            new TestMarshaller<Void>(),
            new TestMarshaller<Void>());
    final ClientTransport transport = mock(ClientTransport.class);
    final ClientStream stream = mock(ClientStream.class);
    ClientTransportProvider provider =
        new ClientTransportProvider() {
          @Override
          public ListenableFuture<ClientTransport> get(CallOptions callOptions) {
            return Futures.immediateFuture(transport);
          }
        };
    when(transport.newStream(
            any(MethodDescriptor.class), any(Metadata.class), any(ClientStreamListener.class)))
        .thenReturn(stream);
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
                descriptor, executor, CallOptions.DEFAULT, provider, deadlineCancellationExecutor)
            .setDecompressorRegistry(decompressorRegistry);

    call.start(new TestClientCallListener<Void>(), new Metadata());

    ArgumentCaptor<Metadata> metadataCaptor = ArgumentCaptor.forClass(Metadata.class);
    verify(transport)
        .newStream(eq(descriptor), metadataCaptor.capture(), isA(ClientStreamListener.class));
    Metadata actual = metadataCaptor.getValue();

    Set<String> acceptedEncodings =
        ImmutableSet.copyOf(actual.getAll(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));
    assertEquals(decompressorRegistry.getAdvertisedMessageEncodings(), acceptedEncodings);
  }
 @Override
 public void updateHeaders(Metadata headers) throws Exception {
   headers.put(AUTHORIZATION_HEADER_KEY, getHeader());
 }