Search in sources :

Example 1 with HttpConnectionResponseInterceptor

use of com.cloudant.http.HttpConnectionResponseInterceptor in project java-cloudant by cloudant.

the class HttpTest method testHttpConnectionRetries.

/**
 * Test the global number of retries
 *
 * @throws Exception
 */
@TestTemplate
public void testHttpConnectionRetries() throws Exception {
    // Just return 200 OK
    mockWebServer.setDispatcher(new MockWebServerResources.ConstantResponseDispatcher(200));
    CloudantClient c = CloudantClientHelper.newMockWebServerClientBuilder(mockWebServer).interceptors(new HttpConnectionResponseInterceptor() {

        @Override
        public HttpConnectionInterceptorContext interceptResponse(HttpConnectionInterceptorContext context) {
            // At least do something with the connection, otherwise we risk breaking it
            try {
                context.connection.getConnection().getResponseCode();
            } catch (IOException e) {
                fail("IOException getting response code");
            }
            // Set to always replay
            context.replayRequest = true;
            return context;
        }
    }).build();
    String response = c.executeRequest(Http.GET(c.getBaseUri()).setNumberOfRetries(5)).responseAsString();
    assertTrue(response.isEmpty(), "There should be no response body on the mock response");
    assertEquals(5, mockWebServer.getRequestCount(), "There should be 5 request attempts");
}
Also used : CloudantClient(com.cloudant.client.api.CloudantClient) HttpConnectionResponseInterceptor(com.cloudant.http.HttpConnectionResponseInterceptor) IOException(java.io.IOException) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) MockWebServerResources(com.cloudant.tests.util.MockWebServerResources) HttpConnectionInterceptorContext(com.cloudant.http.HttpConnectionInterceptorContext) TestTemplate(org.junit.jupiter.api.TestTemplate)

Example 2 with HttpConnectionResponseInterceptor

use of com.cloudant.http.HttpConnectionResponseInterceptor in project java-cloudant by cloudant.

the class Utils method removeReplicatorTestDoc.

public static void removeReplicatorTestDoc(CloudantClient account, String replicatorDocId) throws Exception {
    // Grab replicator doc revision using HTTP HEAD command
    String replicatorDb = "_replicator";
    URI uri = new URIBase(account.getBaseUri()).path(replicatorDb).path(replicatorDocId).build();
    HttpConnection head = Http.HEAD(uri);
    // add a response interceptor to allow us to retrieve the ETag revision header
    final AtomicReference<String> revisionRef = new AtomicReference<String>();
    head.responseInterceptors.add(new HttpConnectionResponseInterceptor() {

        @Override
        public HttpConnectionInterceptorContext interceptResponse(HttpConnectionInterceptorContext context) {
            revisionRef.set(context.connection.getConnection().getHeaderField("ETag"));
            return context;
        }
    });
    account.executeRequest(head);
    String revision = revisionRef.get();
    assertNotNull("The revision should not be null", revision);
    Database replicator = account.database(replicatorDb, false);
    Response removeResponse = replicator.remove(replicatorDocId, revision.replaceAll("\"", ""));
    assertThat(removeResponse.getError(), is(nullValue()));
}
Also used : Response(com.cloudant.client.api.model.Response) HttpConnection(com.cloudant.http.HttpConnection) Database(com.cloudant.client.api.Database) AtomicReference(java.util.concurrent.atomic.AtomicReference) HttpConnectionResponseInterceptor(com.cloudant.http.HttpConnectionResponseInterceptor) HttpConnectionInterceptorContext(com.cloudant.http.HttpConnectionInterceptorContext) URI(java.net.URI) URIBase(com.cloudant.client.internal.URIBase)

Example 3 with HttpConnectionResponseInterceptor

use of com.cloudant.http.HttpConnectionResponseInterceptor in project java-cloudant by cloudant.

the class HttpTest method testInputStreamRetry.

private void testInputStreamRetry(HttpConnection request, byte[] expectedContent) throws Exception {
    final MockResponse retry = new MockResponse().setResponseCode(444);
    mockWebServer.enqueue(retry);
    mockWebServer.enqueue(new MockResponse());
    HttpConnection response = CloudantClientHelper.newMockWebServerClientBuilder(mockWebServer).interceptors(new HttpConnectionResponseInterceptor() {

        // This interceptor responds to our 444 request with a retry
        @Override
        public HttpConnectionInterceptorContext interceptResponse(HttpConnectionInterceptorContext context) {
            try {
                if (444 == context.connection.getConnection().getResponseCode()) {
                    context.replayRequest = true;
                    // Close the error stream
                    InputStream errors = context.connection.getConnection().getErrorStream();
                    if (errors != null) {
                        IOUtils.closeQuietly(errors);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                fail("IOException getting response code in test interceptor");
            }
            return context;
        }
    }).build().executeRequest(request);
    String responseStr = response.responseAsString();
    assertTrue(responseStr.isEmpty(), "There should be no response body on the mock response");
    assertEquals(200, response.getConnection().getResponseCode(), "The final response code should be 200");
    // We want the second request
    assertEquals(2, mockWebServer.getRequestCount(), "There should have been two requests");
    MockWebServerResources.takeRequestWithTimeout(mockWebServer);
    RecordedRequest rr = MockWebServerResources.takeRequestWithTimeout(mockWebServer);
    assertNotNull(rr, "The request should have been recorded");
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream((int) rr.getBodySize());
    rr.getBody().copyTo(byteArrayOutputStream);
    assertArrayEquals(expectedContent, byteArrayOutputStream.toByteArray(), "The body bytes should have matched after a " + "retry");
}
Also used : RecordedRequest(okhttp3.mockwebserver.RecordedRequest) MockResponse(okhttp3.mockwebserver.MockResponse) HttpConnection(com.cloudant.http.HttpConnection) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) HttpConnectionResponseInterceptor(com.cloudant.http.HttpConnectionResponseInterceptor) IOException(java.io.IOException) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) ByteArrayOutputStream(java.io.ByteArrayOutputStream) HttpConnectionInterceptorContext(com.cloudant.http.HttpConnectionInterceptorContext)

Example 4 with HttpConnectionResponseInterceptor

use of com.cloudant.http.HttpConnectionResponseInterceptor in project java-cloudant by cloudant.

the class ClientBuilder method build.

/**
 * Build the {@link CloudantClient} instance based on the endpoint used to construct this
 * client builder and the options that have been set on it before calling this method.
 *
 * @return the {@link CloudantClient} instance for the specified end point and options
 */
public CloudantClient build() {
    logger.config("Building client using URL: " + url);
    // Build properties and couchdb client
    CouchDbProperties props = new CouchDbProperties(url);
    props.addRequestInterceptors(USER_AGENT_INTERCEPTOR);
    if (this.iamApiKey != null) {
        // Create IAM cookie interceptor and set in HttpConnection interceptors
        IamCookieInterceptor cookieInterceptor = new IamCookieInterceptor(this.iamApiKey, this.url.toString());
        props.addRequestInterceptors(cookieInterceptor);
        props.addResponseInterceptors(cookieInterceptor);
        logger.config("Added IAM cookie interceptor");
    } else // Create cookie interceptor
    if (this.username != null && this.password != null) {
        // make interceptor if both username and password are not null
        // Create cookie interceptor and set in HttpConnection interceptors
        CookieInterceptor cookieInterceptor = new CookieInterceptor(username, password, this.url.toString());
        props.addRequestInterceptors(cookieInterceptor);
        props.addResponseInterceptors(cookieInterceptor);
        logger.config("Added cookie interceptor");
    } else {
        // If username or password is null, throw an exception
        if (username != null || password != null) {
            // Username and password both have to contain values
            throw new CouchDbException("Either a username and password must be provided, or " + "both values must be null. Please check the credentials and try again.");
        }
    }
    // If setter methods for read and connection timeout are not called, default values
    // are used.
    logger.config(String.format("Connect timeout: %s %s", connectTimeout, connectTimeoutUnit));
    logger.config(String.format("Read timeout: %s %s", readTimeout, readTimeoutUnit));
    // Log a warning if the DNS cache time is too long
    try {
        boolean shouldLogValueWarning = false;
        boolean isUsingDefaultTTLValue = true;
        String ttlString = Security.getProperty("networkaddress.cache.ttl");
        // Was able to access the property
        if (ttlString != null) {
            try {
                int ttl = Integer.parseInt(ttlString);
                isUsingDefaultTTLValue = false;
                logger.finest("networkaddress.cache.ttl was " + ttl);
                if (ttl > 30 || ttl < 0) {
                    shouldLogValueWarning = true;
                }
            } catch (NumberFormatException nfe) {
                // Suppress the exception, this will result in the default being used
                logger.finest("networkaddress.cache.ttl was not an int.");
            }
        }
        if (isUsingDefaultTTLValue && System.getSecurityManager() != null) {
            // If we're using a default value and there is a SecurityManager we need to warn
            shouldLogValueWarning = true;
        }
        if (shouldLogValueWarning) {
            logger.warning("DNS cache lifetime may be too long. DNS cache lifetimes in excess" + " of 30 seconds may impede client operation during cluster failover.");
        }
    } catch (SecurityException e) {
        // Couldn't access the property; log a warning
        logger.warning("Permission denied to check Java DNS cache TTL. If the cache " + "lifetime is too long cluster failover will be impeded.");
    }
    props.addRequestInterceptors(new TimeoutCustomizationInterceptor(connectTimeout, connectTimeoutUnit, readTimeout, readTimeoutUnit));
    // Set connect options
    props.setMaxConnections(maxConnections);
    props.setProxyURL(proxyURL);
    if (proxyUser != null) {
        // if there was proxy auth information set up proxy auth
        if ("http".equals(url.getProtocol())) {
            // If we are using http, create an interceptor to add the Proxy-Authorization header
            props.addRequestInterceptors(new ProxyAuthInterceptor(proxyUser, proxyPassword));
            logger.config("Added proxy auth interceptor");
        } else {
            // Set up an authenticator
            props.setProxyAuthentication(new PasswordAuthentication(proxyUser, proxyPassword.toCharArray()));
        }
    }
    if (isSSLAuthenticationDisabled) {
        props.addRequestInterceptors(SSLCustomizerInterceptor.SSL_AUTH_DISABLED_INTERCEPTOR);
        logger.config("SSL authentication is disabled");
    }
    if (authenticatedModeSSLSocketFactory != null) {
        props.addRequestInterceptors(new SSLCustomizerInterceptor(authenticatedModeSSLSocketFactory));
        logger.config("Added custom SSL socket factory");
    }
    // Set http connection interceptors
    if (requestInterceptors != null) {
        for (HttpConnectionRequestInterceptor requestInterceptor : requestInterceptors) {
            props.addRequestInterceptors(requestInterceptor);
            logger.config("Added request interceptor: " + requestInterceptor.getClass().getName());
        }
    }
    if (responseInterceptors != null) {
        for (HttpConnectionResponseInterceptor responseInterceptor : responseInterceptors) {
            props.addResponseInterceptors(responseInterceptor);
            logger.config("Added response interceptor: " + responseInterceptor.getClass().getName());
        }
    }
    // if no gsonBuilder has been provided, create a new one
    if (gsonBuilder == null) {
        gsonBuilder = new GsonBuilder();
        logger.config("Using default GSON builder");
    } else {
        logger.config("Using custom GSON builder");
    }
    // always register additional TypeAdapaters for derserializing some Cloudant specific
    // types before constructing the CloudantClient
    gsonBuilder.registerTypeAdapter(DeserializationTypes.SHARDS, new ShardDeserializer()).registerTypeAdapter(DeserializationTypes.INDICES, new IndexDeserializer()).registerTypeAdapter(DeserializationTypes.PERMISSIONS_MAP, new SecurityDeserializer()).registerTypeAdapter(Key.ComplexKey.class, new Key.ComplexKeyDeserializer());
    return new CloudantClient(props, gsonBuilder);
}
Also used : HttpConnectionRequestInterceptor(com.cloudant.http.HttpConnectionRequestInterceptor) CouchDbException(com.cloudant.client.org.lightcouch.CouchDbException) ShardDeserializer(com.cloudant.client.internal.util.ShardDeserializer) IndexDeserializer(com.cloudant.client.internal.util.IndexDeserializer) IamCookieInterceptor(com.cloudant.http.internal.interceptors.IamCookieInterceptor) GsonBuilder(com.google.gson.GsonBuilder) CouchDbProperties(com.cloudant.client.org.lightcouch.CouchDbProperties) SSLCustomizerInterceptor(com.cloudant.http.internal.interceptors.SSLCustomizerInterceptor) ProxyAuthInterceptor(com.cloudant.http.internal.interceptors.ProxyAuthInterceptor) IamCookieInterceptor(com.cloudant.http.internal.interceptors.IamCookieInterceptor) CookieInterceptor(com.cloudant.http.internal.interceptors.CookieInterceptor) SecurityDeserializer(com.cloudant.client.internal.util.SecurityDeserializer) TimeoutCustomizationInterceptor(com.cloudant.http.internal.interceptors.TimeoutCustomizationInterceptor) HttpConnectionResponseInterceptor(com.cloudant.http.HttpConnectionResponseInterceptor) Key(com.cloudant.client.api.views.Key) PasswordAuthentication(java.net.PasswordAuthentication)

Aggregations

HttpConnectionResponseInterceptor (com.cloudant.http.HttpConnectionResponseInterceptor)4 HttpConnectionInterceptorContext (com.cloudant.http.HttpConnectionInterceptorContext)3 HttpConnection (com.cloudant.http.HttpConnection)2 IOException (java.io.IOException)2 CoreMatchers.containsString (org.hamcrest.CoreMatchers.containsString)2 CloudantClient (com.cloudant.client.api.CloudantClient)1 Database (com.cloudant.client.api.Database)1 Response (com.cloudant.client.api.model.Response)1 Key (com.cloudant.client.api.views.Key)1 URIBase (com.cloudant.client.internal.URIBase)1 IndexDeserializer (com.cloudant.client.internal.util.IndexDeserializer)1 SecurityDeserializer (com.cloudant.client.internal.util.SecurityDeserializer)1 ShardDeserializer (com.cloudant.client.internal.util.ShardDeserializer)1 CouchDbException (com.cloudant.client.org.lightcouch.CouchDbException)1 CouchDbProperties (com.cloudant.client.org.lightcouch.CouchDbProperties)1 HttpConnectionRequestInterceptor (com.cloudant.http.HttpConnectionRequestInterceptor)1 CookieInterceptor (com.cloudant.http.internal.interceptors.CookieInterceptor)1 IamCookieInterceptor (com.cloudant.http.internal.interceptors.IamCookieInterceptor)1 ProxyAuthInterceptor (com.cloudant.http.internal.interceptors.ProxyAuthInterceptor)1 SSLCustomizerInterceptor (com.cloudant.http.internal.interceptors.SSLCustomizerInterceptor)1