Search in sources :

Example 11 with CompressionConfig

use of com.linkedin.r2.filter.CompressionConfig in project rest.li by linkedin.

the class TestRequestCompression method testUpdate.

@Test(dataProvider = "requestData")
public void testUpdate(CompressionConfig requestCompressionConfig, String supportedEncodings, RestliRequestOptions restliRequestOptions, int messageLength, String testHelpHeader) throws RemoteInvocationException, CloneNotSupportedException, InterruptedException, ExecutionException, TimeoutException {
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("R2 Netty Scheduler"));
    Map<String, CompressionConfig> requestCompressionConfigs = new HashMap<String, CompressionConfig>();
    if (requestCompressionConfig != null) {
        requestCompressionConfigs.put(SERVICE_NAME, requestCompressionConfig);
    }
    HttpClientFactory httpClientFactory = new HttpClientFactory(FilterChains.empty(), new NioEventLoopGroup(), true, executor, true, null, false, AbstractJmxManager.NULL_JMX_MANAGER, // The default compression threshold is between small and large.
    500, requestCompressionConfigs);
    Map<String, String> properties = new HashMap<String, String>();
    properties.put(HttpClientFactory.HTTP_REQUEST_CONTENT_ENCODINGS, supportedEncodings);
    properties.put(HttpClientFactory.HTTP_SERVICE_NAME, SERVICE_NAME);
    TransportClientAdapter clientAdapter1 = new TransportClientAdapter(httpClientFactory.getClient(properties));
    RestClient client = new RestClient(clientAdapter1, FILTERS_URI_PREFIX);
    RootBuilderWrapper<Long, Greeting> builders = new RootBuilderWrapper<Long, Greeting>(new GreetingsRequestBuilders(restliRequestOptions));
    // GET
    Request<Greeting> request = builders.get().id(1L).build();
    ResponseFuture<Greeting> future = client.sendRequest(request);
    Response<Greeting> greetingResponse = future.getResponse();
    String response1 = greetingResponse.getEntity().getMessage();
    Assert.assertNotNull(response1);
    // POST
    Greeting greeting = new Greeting(greetingResponse.getEntity().data().copy());
    char[] As = new char[messageLength];
    Arrays.fill(As, 'A');
    String message = new String(As);
    greeting.setMessage(message);
    Request<EmptyRecord> writeRequest = builders.update().id(1L).input(greeting).setHeader(TEST_HELP_HEADER, testHelpHeader).build();
    client.sendRequest(writeRequest).getResponse();
    // GET again, to verify that our POST worked.
    Request<Greeting> request2 = builders.get().id(1L).build();
    ResponseFuture<Greeting> future2 = client.sendRequest(request2);
    String response2 = future2.getResponse().getEntity().getMessage();
    Assert.assertEquals(response2, message);
    FutureCallback<None> callback1 = new FutureCallback<None>();
    client.shutdown(callback1);
    callback1.get(30, TimeUnit.SECONDS);
    FutureCallback<None> callback2 = new FutureCallback<None>();
    httpClientFactory.shutdown(callback2);
    callback2.get(30, TimeUnit.SECONDS);
}
Also used : Greeting(com.linkedin.restli.examples.greetings.api.Greeting) EmptyRecord(com.linkedin.restli.common.EmptyRecord) HashMap(java.util.HashMap) GreetingsRequestBuilders(com.linkedin.restli.examples.greetings.client.GreetingsRequestBuilders) TransportClientAdapter(com.linkedin.r2.transport.common.bridge.client.TransportClientAdapter) HttpClientFactory(com.linkedin.r2.transport.http.client.HttpClientFactory) NioEventLoopGroup(io.netty.channel.nio.NioEventLoopGroup) FutureCallback(com.linkedin.common.callback.FutureCallback) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) NamedThreadFactory(com.linkedin.r2.util.NamedThreadFactory) RootBuilderWrapper(com.linkedin.restli.test.util.RootBuilderWrapper) RestClient(com.linkedin.restli.client.RestClient) None(com.linkedin.common.util.None) CompressionConfig(com.linkedin.r2.filter.CompressionConfig) Test(org.testng.annotations.Test)

Example 12 with CompressionConfig

use of com.linkedin.r2.filter.CompressionConfig in project rest.li by linkedin.

the class TestResponseCompression method requestData.

@DataProvider(name = "requestData")
private Object[][] requestData() {
    Integer zero = 0;
    Integer tiny = 100;
    Integer huge = 1000000;
    Integer max = Integer.MAX_VALUE;
    int largeIdCount = 100;
    int smallIdCount = 1;
    RestliRequestOptions forceOnOption = new RestliRequestOptionsBuilder().setProtocolVersionOption(ProtocolVersionOption.USE_LATEST_IF_AVAILABLE).setResponseCompressionOverride(CompressionOption.FORCE_ON).build();
    RestliRequestOptions forceOffOption = new RestliRequestOptionsBuilder().setProtocolVersionOption(ProtocolVersionOption.USE_LATEST_IF_AVAILABLE).setResponseCompressionOverride(CompressionOption.FORCE_OFF).build();
    return new Object[][] { // Large responses are compressed
    { true, null, RestliRequestOptions.DEFAULT_OPTIONS, largeIdCount, DEFAULT_ACCEPT_ENCODING, null, true }, { true, null, RestliRequestOptions.DEFAULT_OPTIONS, smallIdCount, DEFAULT_ACCEPT_ENCODING, null, false }, // Override the default threshold and cause small responses to be compressed
    { true, new CompressionConfig(tiny), RestliRequestOptions.DEFAULT_OPTIONS, largeIdCount, DEFAULT_ACCEPT_ENCODING, tiny.toString(), true }, { true, new CompressionConfig(tiny), RestliRequestOptions.DEFAULT_OPTIONS, smallIdCount, DEFAULT_ACCEPT_ENCODING, tiny.toString(), true }, // Override the default threshold and cause large responses to be NOT compressed
    { true, new CompressionConfig(huge), RestliRequestOptions.DEFAULT_OPTIONS, largeIdCount, DEFAULT_ACCEPT_ENCODING, huge.toString(), false }, { true, new CompressionConfig(huge), RestliRequestOptions.DEFAULT_OPTIONS, smallIdCount, DEFAULT_ACCEPT_ENCODING, huge.toString(), false }, // Force on/off using RestliRequestOptions
    { true, null, forceOnOption, largeIdCount, DEFAULT_ACCEPT_ENCODING, zero.toString(), true }, { true, null, forceOnOption, smallIdCount, DEFAULT_ACCEPT_ENCODING, zero.toString(), true }, { true, new CompressionConfig(huge), forceOnOption, smallIdCount, DEFAULT_ACCEPT_ENCODING, zero.toString(), true }, { true, null, forceOffOption, largeIdCount, NONE, null, false }, { true, null, forceOffOption, smallIdCount, NONE, null, false }, { true, new CompressionConfig(huge), forceOffOption, largeIdCount, NONE, null, false }, // Force on/off using ResponseCompressionConfig
    { true, new CompressionConfig(0), RestliRequestOptions.DEFAULT_OPTIONS, largeIdCount, DEFAULT_ACCEPT_ENCODING, zero.toString(), true }, { true, new CompressionConfig(0), RestliRequestOptions.DEFAULT_OPTIONS, smallIdCount, DEFAULT_ACCEPT_ENCODING, zero.toString(), true }, { true, new CompressionConfig(Integer.MAX_VALUE), RestliRequestOptions.DEFAULT_OPTIONS, largeIdCount, DEFAULT_ACCEPT_ENCODING, max.toString(), false }, { true, new CompressionConfig(Integer.MAX_VALUE), RestliRequestOptions.DEFAULT_OPTIONS, smallIdCount, DEFAULT_ACCEPT_ENCODING, max.toString(), false }, // RestliRequestOptions takes precedence over ResponseCompressionConfig
    { true, new CompressionConfig(0), forceOffOption, largeIdCount, NONE, null, false }, { true, new CompressionConfig(Integer.MAX_VALUE), forceOnOption, smallIdCount, DEFAULT_ACCEPT_ENCODING, zero.toString(), true }, // If http.useResponseCompression is false or null, Accept-Encoding header is not sent and response is not compressed
    { false, null, RestliRequestOptions.DEFAULT_OPTIONS, largeIdCount, NONE, null, false }, { false, new CompressionConfig(tiny), RestliRequestOptions.DEFAULT_OPTIONS, largeIdCount, NONE, null, false }, { false, null, forceOnOption, largeIdCount, NONE, null, false }, { null, new CompressionConfig(0), RestliRequestOptions.DEFAULT_OPTIONS, largeIdCount, NONE, null, false }, { null, new CompressionConfig(Integer.MAX_VALUE), forceOnOption, smallIdCount, NONE, null, false } };
}
Also used : RestliRequestOptions(com.linkedin.restli.client.RestliRequestOptions) RestliRequestOptionsBuilder(com.linkedin.restli.client.RestliRequestOptionsBuilder) CompressionConfig(com.linkedin.r2.filter.CompressionConfig) DataProvider(org.testng.annotations.DataProvider)

Example 13 with CompressionConfig

use of com.linkedin.r2.filter.CompressionConfig in project rest.li by linkedin.

the class TestResponseCompression method initClass.

@BeforeClass
public void initClass() throws Exception {
    class TestHelperFilter implements Filter {

        @Override
        public CompletableFuture<Void> onRequest(FilterRequestContext requestContext) {
            Map<String, String> requestHeaders = requestContext.getRequestHeaders();
            if (requestHeaders.containsKey(EXPECTED_ACCEPT_ENCODING)) {
                String expected = requestHeaders.get(EXPECTED_ACCEPT_ENCODING);
                if (expected.equals(NONE)) {
                    if (requestHeaders.containsKey(HttpConstants.ACCEPT_ENCODING)) {
                        throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Accept-Encoding header should not be present.");
                    }
                } else {
                    if (!expected.equals(requestHeaders.get(HttpConstants.ACCEPT_ENCODING))) {
                        throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Accept-Encoding header should be " + expected + ", but received " + requestHeaders.get(HttpConstants.ACCEPT_ENCODING));
                    }
                }
            }
            if (requestHeaders.containsKey(EXPECTED_COMPRESSION_THRESHOLD)) {
                if (!requestHeaders.get(EXPECTED_COMPRESSION_THRESHOLD).equals(requestHeaders.get(HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD))) {
                    throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Expected " + HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD + " " + requestHeaders.get(EXPECTED_COMPRESSION_THRESHOLD) + ", but received " + requestHeaders.get(HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD));
                }
            }
            return CompletableFuture.completedFuture(null);
        }
    }
    // The default compression threshold is between tiny and huge threshold.
    final FilterChain fc = FilterChains.empty().addLastRest(new TestCompressionServer.SaveContentEncodingHeaderFilter()).addLastRest(new ServerCompressionFilter("x-snappy-framed,snappy,gzip,deflate", new CompressionConfig(10000))).addLastRest(new SimpleLoggingFilter());
    super.init(Arrays.asList(new TestHelperFilter()), fc, false);
}
Also used : ServerCompressionFilter(com.linkedin.r2.filter.compression.ServerCompressionFilter) FilterChain(com.linkedin.r2.filter.FilterChain) SimpleLoggingFilter(com.linkedin.r2.filter.logging.SimpleLoggingFilter) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) SimpleLoggingFilter(com.linkedin.r2.filter.logging.SimpleLoggingFilter) Filter(com.linkedin.restli.server.filter.Filter) ServerCompressionFilter(com.linkedin.r2.filter.compression.ServerCompressionFilter) FilterRequestContext(com.linkedin.restli.server.filter.FilterRequestContext) CompressionConfig(com.linkedin.r2.filter.CompressionConfig) BeforeClass(org.testng.annotations.BeforeClass)

Example 14 with CompressionConfig

use of com.linkedin.r2.filter.CompressionConfig in project rest.li by linkedin.

the class HttpClientFactory method getClient.

/**
   * Create a new {@link TransportClient} with the specified properties,
   * {@link SSLContext} and {@link SSLParameters}
   *
   * @param properties map of properties for the {@link TransportClient}
   * @param sslContext {@link SSLContext} to be used for requests over SSL/TLS.
   * @param sslParameters {@link SSLParameters} to configure secure connections.
   * @return an appropriate {@link TransportClient} instance, as specified by the properties.
   */
private TransportClient getClient(Map<String, ? extends Object> properties, SSLContext sslContext, SSLParameters sslParameters) {
    LOG.info("Getting a client with configuration {} and SSLContext {}", properties, sslContext);
    TransportClient client = getRawClient(properties, sslContext, sslParameters);
    List<String> httpRequestServerSupportedEncodings = ConfigValueExtractor.buildList(properties.remove(HTTP_REQUEST_CONTENT_ENCODINGS), LIST_SEPARATOR);
    // In the old model, responses were compressed according to the type of method, so clients would send
    // the Accept-Encoding header if the method was in HTTP_RESPONSE_COMPRESSION_OPERATIONS.
    // In the new model, responses are compressed according to its size, so clients send the Accept-Encoding header
    // if the server enabled response compression by setting HTTP_USE_RESPONSE_COMPRESSION to true.
    // Until all servers migrate to the new model, clients will understand both models,
    // and send the Accept-Encoding header if either the old or the new criterion is satisfied.
    List<String> httpResponseCompressionOperations = ConfigValueExtractor.buildList(properties.remove(HTTP_RESPONSE_COMPRESSION_OPERATIONS), LIST_SEPARATOR);
    String useResponseCompressionProperty = (String) properties.get(HTTP_USE_RESPONSE_COMPRESSION);
    if (useResponseCompressionProperty != null && Boolean.parseBoolean(useResponseCompressionProperty)) {
        httpResponseCompressionOperations.add(ClientCompressionHelper.COMPRESS_ALL_RESPONSES_INDICATOR);
    }
    FilterChain filters = _filters;
    if (_useClientCompression) {
        List<String> responseEncodings = null;
        if (properties.containsKey(HTTP_RESPONSE_CONTENT_ENCODINGS)) {
            responseEncodings = ConfigValueExtractor.buildList(properties.remove(HTTP_RESPONSE_CONTENT_ENCODINGS), LIST_SEPARATOR);
        }
        String httpServiceName = (String) properties.get(HTTP_SERVICE_NAME);
        EncodingType restRequestContentEncoding = getRestRequestContentEncoding(httpRequestServerSupportedEncodings);
        StreamEncodingType streamRequestContentEncoding = getStreamRequestContentEncoding(httpRequestServerSupportedEncodings);
        if (restRequestContentEncoding != EncodingType.IDENTITY || !httpResponseCompressionOperations.isEmpty()) {
            filters = filters.addLastRest(new ClientCompressionFilter(restRequestContentEncoding, getRestRequestCompressionConfig(httpServiceName, restRequestContentEncoding), buildRestAcceptEncodingSchemaNames(responseEncodings), _responseCompressionConfigs.get(httpServiceName), httpResponseCompressionOperations));
        }
        if (streamRequestContentEncoding != StreamEncodingType.IDENTITY || !httpResponseCompressionOperations.isEmpty()) {
            CompressionConfig compressionConfig = getStreamRequestCompressionConfig(httpServiceName, streamRequestContentEncoding);
            filters = filters.addLast(new ClientStreamCompressionFilter(streamRequestContentEncoding, compressionConfig, buildStreamAcceptEncodingSchemas(responseEncodings), _responseCompressionConfigs.get(httpServiceName), httpResponseCompressionOperations, _compressionExecutor));
        }
    }
    Integer queryPostThreshold = chooseNewOverDefault(getIntValue(properties, HTTP_QUERY_POST_THRESHOLD), Integer.MAX_VALUE);
    ClientQueryTunnelFilter clientQueryTunnelFilter = new ClientQueryTunnelFilter(queryPostThreshold);
    filters = filters.addLastRest(clientQueryTunnelFilter);
    filters = filters.addLast(clientQueryTunnelFilter);
    // Add the disruptor filter to the end of the filter chain to get the most accurate simulation of disrupt
    Integer requestTimeout = chooseNewOverDefault(getIntValue(properties, HTTP_REQUEST_TIMEOUT), DEFAULT_REQUEST_TIMEOUT);
    DisruptFilter disruptFilter = new DisruptFilter(_executor, _eventLoopGroup, requestTimeout);
    filters = filters.addLastRest(disruptFilter);
    filters = filters.addLast(disruptFilter);
    client = new FilterChainClient(client, filters);
    client = new FactoryClient(client);
    synchronized (_mutex) {
        if (!_running) {
            throw new IllegalStateException("Factory is shutting down");
        }
        _clientsOutstanding++;
        return client;
    }
}
Also used : TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) FilterChain(com.linkedin.r2.filter.FilterChain) StreamEncodingType(com.linkedin.r2.filter.compression.streaming.StreamEncodingType) EncodingType(com.linkedin.r2.filter.compression.EncodingType) DisruptFilter(com.linkedin.r2.disruptor.DisruptFilter) StreamEncodingType(com.linkedin.r2.filter.compression.streaming.StreamEncodingType) ClientStreamCompressionFilter(com.linkedin.r2.filter.compression.ClientStreamCompressionFilter) FilterChainClient(com.linkedin.r2.filter.transport.FilterChainClient) ClientQueryTunnelFilter(com.linkedin.r2.filter.transport.ClientQueryTunnelFilter) ClientCompressionFilter(com.linkedin.r2.filter.compression.ClientCompressionFilter) CompressionConfig(com.linkedin.r2.filter.CompressionConfig)

Example 15 with CompressionConfig

use of com.linkedin.r2.filter.CompressionConfig in project rest.li by linkedin.

the class TestCompressionEcho method compressionEchoData.

@DataProvider
public Object[][] compressionEchoData() {
    StreamEncodingType[] encodings = new StreamEncodingType[] { StreamEncodingType.GZIP, StreamEncodingType.DEFLATE, StreamEncodingType.SNAPPY_FRAMED, StreamEncodingType.BZIP2, StreamEncodingType.IDENTITY };
    Object[][] args = new Object[2 * encodings.length * encodings.length][2];
    int cur = 0;
    for (StreamEncodingType requestEncoding : encodings) {
        for (StreamEncodingType acceptEncoding : encodings) {
            StreamFilter clientCompressionFilter = new ClientStreamCompressionFilter(requestEncoding, new CompressionConfig(THRESHOLD), new StreamEncodingType[] { acceptEncoding }, new CompressionConfig(THRESHOLD), Arrays.asList(new String[] { "*" }), _executor);
            TransportClientFactory factory = new HttpClientFactory.Builder().setFilterChain(FilterChains.createStreamChain(clientCompressionFilter)).build();
            Client client = new TransportClientAdapter(factory.getClient(getClientProperties()), true);
            args[cur][0] = client;
            args[cur][1] = LARGE_BYTES_NUM;
            cur++;
            _clientFactories.add(factory);
            _clients.add(client);
        }
    }
    // test data that won't trigger compression
    for (StreamEncodingType requestEncoding : encodings) {
        for (StreamEncodingType acceptEncoding : encodings) {
            StreamFilter clientCompressionFilter = new ClientStreamCompressionFilter(requestEncoding, new CompressionConfig(THRESHOLD), new StreamEncodingType[] { acceptEncoding }, new CompressionConfig(THRESHOLD), Arrays.asList(new String[] { "*" }), _executor);
            TransportClientFactory factory = new HttpClientFactory.Builder().setFilterChain(FilterChains.createStreamChain(clientCompressionFilter)).build();
            Client client = new TransportClientAdapter(factory.getClient(getClientProperties()), true);
            args[cur][0] = client;
            args[cur][1] = SMALL_BYTES_NUM;
            cur++;
            _clientFactories.add(factory);
            _clients.add(client);
        }
    }
    return args;
}
Also used : StreamRequestBuilder(com.linkedin.r2.message.stream.StreamRequestBuilder) StreamResponseBuilder(com.linkedin.r2.message.stream.StreamResponseBuilder) TransportDispatcherBuilder(com.linkedin.r2.transport.common.bridge.server.TransportDispatcherBuilder) StreamFilter(com.linkedin.r2.filter.message.stream.StreamFilter) StreamEncodingType(com.linkedin.r2.filter.compression.streaming.StreamEncodingType) ClientStreamCompressionFilter(com.linkedin.r2.filter.compression.ClientStreamCompressionFilter) TransportClientAdapter(com.linkedin.r2.transport.common.bridge.client.TransportClientAdapter) Client(com.linkedin.r2.transport.common.Client) TransportClientFactory(com.linkedin.r2.transport.common.TransportClientFactory) CompressionConfig(com.linkedin.r2.filter.CompressionConfig) DataProvider(org.testng.annotations.DataProvider)

Aggregations

CompressionConfig (com.linkedin.r2.filter.CompressionConfig)20 DataProvider (org.testng.annotations.DataProvider)9 Test (org.testng.annotations.Test)8 StreamRequestBuilder (com.linkedin.r2.message.stream.StreamRequestBuilder)6 TransportClientAdapter (com.linkedin.r2.transport.common.bridge.client.TransportClientAdapter)6 RequestContext (com.linkedin.r2.message.RequestContext)5 URI (java.net.URI)5 HashMap (java.util.HashMap)5 ByteString (com.linkedin.data.ByteString)4 ClientStreamCompressionFilter (com.linkedin.r2.filter.compression.ClientStreamCompressionFilter)4 StreamEncodingType (com.linkedin.r2.filter.compression.streaming.StreamEncodingType)4 Client (com.linkedin.r2.transport.common.Client)4 TransportClientFactory (com.linkedin.r2.transport.common.TransportClientFactory)4 TransportDispatcherBuilder (com.linkedin.r2.transport.common.bridge.server.TransportDispatcherBuilder)4 FilterChain (com.linkedin.r2.filter.FilterChain)3 StreamFilter (com.linkedin.r2.filter.message.stream.StreamFilter)3 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)3 StreamRequest (com.linkedin.r2.message.stream.StreamRequest)3 ByteArrayInputStream (java.io.ByteArrayInputStream)3 FutureCallback (com.linkedin.common.callback.FutureCallback)2