/*
* Copyright (c) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.api.client.http;
import com.google.api.client.testing.http.HttpTesting;
import com.google.api.client.testing.http.MockHttpTransport;
import com.google.api.client.testing.http.MockHttpUnsuccessfulResponseHandler;
import com.google.api.client.testing.http.MockLowLevelHttpRequest;
import com.google.api.client.testing.http.MockLowLevelHttpResponse;
import com.google.api.client.testing.util.LogRecordingHandler;
import com.google.api.client.testing.util.MockBackOff;
import com.google.api.client.testing.util.MockSleeper;
import com.google.api.client.util.BackOff;
import com.google.api.client.util.Key;
import com.google.api.client.util.LoggingStreamingContent;
import com.google.api.client.util.StringUtils;
import com.google.api.client.util.Value;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import junit.framework.Assert;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
/**
* Tests {@link HttpRequest}.
*
* @author Yaniv Inbar
*/
public class HttpRequestTest extends TestCase {
private static final Set<String> BASIC_METHODS =
ImmutableSet.of(HttpMethods.GET, HttpMethods.PUT, HttpMethods.POST, HttpMethods.DELETE);
private static final Set<String> OTHER_METHODS =
ImmutableSet.of(HttpMethods.HEAD, HttpMethods.PATCH);
public HttpRequestTest(String name) {
super(name);
}
@Override
public void setUp() {
// suppress logging warnings to the console
HttpTransport.LOGGER.setLevel(java.util.logging.Level.SEVERE);
}
@Override
public void tearDown() {
// back to the standard logging level for console
HttpTransport.LOGGER.setLevel(java.util.logging.Level.WARNING);
}
public void testNotSupportedByDefault() throws Exception {
MockHttpTransport transport = new MockHttpTransport();
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
for (String method : BASIC_METHODS) {
request.setRequestMethod(method);
request.execute();
}
for (String method : OTHER_METHODS) {
transport =
new MockHttpTransport.Builder().setSupportedMethods(ImmutableSet.<String>of()).build();
request = transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
request.setRequestMethod(method);
try {
request.execute();
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
}
transport =
new MockHttpTransport.Builder().setSupportedMethods(ImmutableSet.of(method)).build();
request = transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
request.setRequestMethod(method);
request.execute();
}
}
static class MockExecutor implements Executor {
private Runnable runnable;
public void actuallyRun() {
runnable.run();
}
public void execute(Runnable command) {
this.runnable = command;
}
}
@Deprecated
static private class MockBackOffPolicy implements BackOffPolicy {
int backOffCalls;
int resetCalls;
boolean returnBackOffStop;
MockBackOffPolicy() {
}
public boolean isBackOffRequired(int statusCode) {
switch (statusCode) {
case HttpStatusCodes.STATUS_CODE_SERVER_ERROR: // 500
case HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE: // 503
return true;
default:
return false;
}
}
public void reset() {
resetCalls++;
}
public long getNextBackOffMillis() {
backOffCalls++;
if (returnBackOffStop) {
return BackOffPolicy.STOP;
}
return 0;
}
}
/**
* Transport used for testing the redirection logic in HttpRequest.
*/
static class RedirectTransport extends MockHttpTransport {
int lowLevelExecCalls;
boolean removeLocation;
boolean infiniteRedirection;
int redirectStatusCode = HttpStatusCodes.STATUS_CODE_MOVED_PERMANENTLY;
String[] expectedContent;
LowLevelHttpRequest retryableGetRequest = new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
if (expectedContent != null) {
assertEquals(String.valueOf(lowLevelExecCalls), expectedContent[lowLevelExecCalls],
getContentAsString());
}
lowLevelExecCalls++;
if (infiniteRedirection || lowLevelExecCalls == 1) {
// Return redirect on only the first call.
// If infiniteRedirection is true then always return the redirect status code.
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
response.setStatusCode(redirectStatusCode);
if (!removeLocation) {
response.addHeader("Location", HttpTesting.SIMPLE_URL);
}
return response;
}
// Return success on the second if infiniteRedirection is False.
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
response.setContent("{\"data\":{\"foo\":{\"v1\":{}}}}");
return response;
}
};
@Override
public LowLevelHttpRequest buildRequest(String method, String url) {
return retryableGetRequest;
}
}
private void setBackOffUnsuccessfulResponseHandler(
HttpRequest request, BackOff backOff, final HttpUnsuccessfulResponseHandler handler) {
final HttpBackOffUnsuccessfulResponseHandler backOffHandler =
new HttpBackOffUnsuccessfulResponseHandler(backOff).setSleeper(new MockSleeper());
request.setUnsuccessfulResponseHandler(new HttpUnsuccessfulResponseHandler() {
public boolean handleResponse(
HttpRequest request, HttpResponse response, boolean supportsRetry) throws IOException {
return handler.handleResponse(request, response, supportsRetry)
|| backOffHandler.handleResponse(request, response, supportsRetry);
}
});
}
public void test301Redirect() throws Exception {
// Set up RedirectTransport to redirect on the first request and then return success.
RedirectTransport fakeTransport = new RedirectTransport();
HttpRequest request =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://gmail.com"));
HttpResponse resp = request.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
}
@Deprecated
public void test301RedirectWithUnsuccessfulResponseHandled() throws Exception {
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(true);
MockBackOffPolicy backOffPolicy = new MockBackOffPolicy();
// Set up RedirectTransport to redirect on the first request and then return success.
RedirectTransport fakeTransport = new RedirectTransport();
HttpRequest request =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://gmail.com"));
request.setUnsuccessfulResponseHandler(handler);
request.setBackOffPolicy(backOffPolicy);
HttpResponse resp = request.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
// Assert that the redirect logic was not invoked because the response handler could handle the
// request. The request url should be the original http://gmail.com
Assert.assertEquals("http://gmail.com", request.getUrl().toString());
// Assert that the backoff policy was not invoked because the response handler could handle the
// request.
Assert.assertEquals(1, backOffPolicy.resetCalls);
Assert.assertEquals(0, backOffPolicy.backOffCalls);
Assert.assertTrue(handler.isCalled());
}
public void test301RedirectWithBackOffUnsuccessfulResponseHandled() throws Exception {
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(true);
// Set up RedirectTransport to redirect on the first request and then return success.
RedirectTransport fakeTransport = new RedirectTransport();
HttpRequest request =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://gmail.com"));
MockBackOff backOff = new MockBackOff();
setBackOffUnsuccessfulResponseHandler(request, backOff, handler);
HttpResponse resp = request.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
// Assert that the redirect logic was not invoked because the response handler could handle the
// request. The request url should be the original http://gmail.com
Assert.assertEquals("http://gmail.com", request.getUrl().toString());
// Assert that the backoff was not invoked since the response handler could handle the request
Assert.assertEquals(0, backOff.getNumberOfTries());
Assert.assertTrue(handler.isCalled());
}
@Deprecated
public void test301RedirectWithUnsuccessfulResponseNotHandled() throws Exception {
// Create an Unsuccessful response handler that always returns false.
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
MockBackOffPolicy backOffPolicy = new MockBackOffPolicy();
// Set up RedirectTransport to redirect on the first request and then return success.
RedirectTransport fakeTransport = new RedirectTransport();
HttpRequest request =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://gmail.com"));
request.setUnsuccessfulResponseHandler(handler);
request.setBackOffPolicy(backOffPolicy);
HttpResponse resp = request.execute();
Assert.assertEquals(200, resp.getStatusCode());
// Assert that the redirect logic was invoked because the response handler could not handle the
// request. The request url should have changed from http://gmail.com to http://google.com
Assert.assertEquals(HttpTesting.SIMPLE_URL, request.getUrl().toString());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
// Assert that the backoff policy is never invoked (except to reset) because the response
// handler returned false.
Assert.assertEquals(1, backOffPolicy.resetCalls);
Assert.assertEquals(0, backOffPolicy.backOffCalls);
}
public void test301RedirectWithBackOffUnsuccessfulResponseNotHandled() throws Exception {
// Create an Unsuccessful response handler that always returns false.
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
// Set up RedirectTransport to redirect on the first request and then return success.
RedirectTransport fakeTransport = new RedirectTransport();
HttpRequest request =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://gmail.com"));
MockBackOff backOff = new MockBackOff();
setBackOffUnsuccessfulResponseHandler(request, backOff, handler);
HttpResponse resp = request.execute();
Assert.assertEquals(200, resp.getStatusCode());
// Assert that the redirect logic was invoked because the response handler could not handle the
// request. The request url should have changed from http://gmail.com to http://google.com
Assert.assertEquals(HttpTesting.SIMPLE_URL, request.getUrl().toString());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
// Assert that the backoff was not invoked since it's not required for 3xx errors
Assert.assertEquals(0, backOff.getNumberOfTries());
}
public void test303Redirect() throws Exception {
// Set up RedirectTransport to redirect on the first request and then return success.
RedirectTransport fakeTransport = new RedirectTransport();
fakeTransport.redirectStatusCode = HttpStatusCodes.STATUS_CODE_SEE_OTHER;
byte[] content = new byte[300];
Arrays.fill(content, (byte) ' ');
HttpRequest request = fakeTransport.createRequestFactory()
.buildPostRequest(new GenericUrl("http://gmail.com"), new ByteArrayContent(null, content));
request.setRequestMethod(HttpMethods.POST);
HttpResponse resp = request.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
// Assert that the method in the request was changed to a GET due to the 303.
Assert.assertEquals(HttpMethods.GET, request.getRequestMethod());
// Assert that the content is null, since GET requests don't support non-zero content-length
Assert.assertNull(request.getContent());
}
public void testInfiniteRedirects() throws Exception {
// Set up RedirectTransport to cause infinite redirections.
RedirectTransport fakeTransport = new RedirectTransport();
fakeTransport.infiniteRedirection = true;
HttpRequest request =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://gmail.com"));
try {
request.execute();
fail("expected HttpResponseException");
} catch (HttpResponseException e) {
}
// Should be called 1 more than the number of retries allowed (because the first request is not
// counted as a retry).
Assert.assertEquals(request.getNumberOfRetries() + 1, fakeTransport.lowLevelExecCalls);
}
public void testMissingLocationRedirect() throws Exception {
// Set up RedirectTransport to set responses with missing location headers.
RedirectTransport fakeTransport = new RedirectTransport();
fakeTransport.removeLocation = true;
HttpRequest request =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://gmail.com"));
try {
request.execute();
fail("expected HttpResponseException");
} catch (HttpResponseException e) {
}
Assert.assertEquals(1, fakeTransport.lowLevelExecCalls);
}
static private class FailThenSuccessBackoffTransport extends MockHttpTransport {
public int lowLevelExecCalls;
int errorStatusCode;
int callsBeforeSuccess;
protected FailThenSuccessBackoffTransport(int errorStatusCode, int callsBeforeSuccess) {
this.errorStatusCode = errorStatusCode;
this.callsBeforeSuccess = callsBeforeSuccess;
}
public LowLevelHttpRequest retryableGetRequest = new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() {
lowLevelExecCalls++;
if (lowLevelExecCalls <= callsBeforeSuccess) {
// Return failure on the first call
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
response.setContent("INVALID TOKEN");
response.setStatusCode(errorStatusCode);
return response;
}
// Return success on the second
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
response.setContent("{\"data\":{\"foo\":{\"v1\":{}}}}");
response.setStatusCode(200);
return response;
}
};
@Override
public LowLevelHttpRequest buildRequest(String method, String url) {
return retryableGetRequest;
}
}
static private class FailThenSuccessConnectionErrorTransport extends MockHttpTransport {
public int lowLevelExecCalls;
int callsBeforeSuccess;
List<String> userAgentHeader = Lists.newArrayList();
protected FailThenSuccessConnectionErrorTransport(int callsBeforeSuccess) {
this.callsBeforeSuccess = callsBeforeSuccess;
}
@Override
public LowLevelHttpRequest buildRequest(String method, String url) {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
lowLevelExecCalls++;
userAgentHeader = getHeaderValues("User-Agent");
if (lowLevelExecCalls <= callsBeforeSuccess) {
throw new IOException();
}
// Return success when count is more than callsBeforeSuccess
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
response.setStatusCode(200);
return response;
}
};
}
}
static private class StatusCodesTransport extends MockHttpTransport {
int statusCode = 200;
public StatusCodesTransport() {
}
public MockLowLevelHttpRequest retryableGetRequest = new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
response.setStatusCode(statusCode);
return response;
}
};
@Override
public LowLevelHttpRequest buildRequest(String method, String url) {
return retryableGetRequest;
}
}
public void testHandleRedirect() throws Exception {
StatusCodesTransport transport = new StatusCodesTransport();
HttpRequest req =
transport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
HttpResponse response = req.execute();
// 200 should not be redirected
assertFalse(req.handleRedirect(response.getStatusCode(), response.getHeaders()));
subtestRedirect(301, true);
subtestRedirect(302, true);
subtestRedirect(303, true);
subtestRedirect(307, true);
subtestRedirect(307, false);
}
private void subtestRedirect(int statusCode, boolean setLocation) throws Exception {
StatusCodesTransport transport = new StatusCodesTransport();
transport.statusCode = statusCode;
HttpRequest req =
transport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setThrowExceptionOnExecuteError(false);
req.getHeaders()
.setAuthorization("auth")
.setIfMatch("etag")
.setIfNoneMatch("etag")
.setIfModifiedSince("date")
.setIfUnmodifiedSince("date")
.setIfRange("range");
HttpResponse response = req.execute();
if (setLocation) {
response.getHeaders().setLocation("http://redirect/location");
}
boolean handleRedirect = req.handleRedirect(response.getStatusCode(), response.getHeaders());
if (setLocation) {
assertTrue(handleRedirect);
assertNull(req.getHeaders().getAuthorization());
assertNull(req.getHeaders().getIfMatch());
assertNull(req.getHeaders().getIfNoneMatch());
assertNull(req.getHeaders().getIfModifiedSince());
assertNull(req.getHeaders().getIfUnmodifiedSince());
assertNull(req.getHeaders().getIfRange());
assertEquals("http://redirect/location", req.getUrl().toString());
} else {
assertFalse(handleRedirect);
assertEquals("auth", req.getHeaders().getAuthorization());
assertEquals("etag", req.getHeaders().getIfMatch());
assertEquals("etag", req.getHeaders().getIfNoneMatch());
assertEquals("date", req.getHeaders().getIfModifiedSince());
assertEquals("date", req.getHeaders().getIfUnmodifiedSince());
assertEquals("range", req.getHeaders().getIfRange());
assertEquals("http://not/used", req.getUrl().toString());
}
}
public void testHandleRedirect_relativeLocation() throws IOException {
subtestHandleRedirect_relativeLocation("http://some.org/a/b", "z", "http://some.org/a/z");
subtestHandleRedirect_relativeLocation("http://some.org/a/b", "z/", "http://some.org/a/z/");
subtestHandleRedirect_relativeLocation("http://some.org/a/b", "/z", "http://some.org/z");
subtestHandleRedirect_relativeLocation("http://some.org/a/b", "x/z", "http://some.org/a/x/z");
subtestHandleRedirect_relativeLocation(
"http://some.org/a/b", "http://other.org/c", "http://other.org/c");
}
public void subtestHandleRedirect_relativeLocation(
String curLocation, String relLocation, String newLocation) throws IOException {
HttpTransport transport = new MockHttpTransport();
HttpRequest req = transport.createRequestFactory().buildGetRequest(new GenericUrl(curLocation));
HttpHeaders responseHeaders = new HttpHeaders().setLocation(relLocation);
req.handleRedirect(HttpStatusCodes.STATUS_CODE_SEE_OTHER, responseHeaders);
assertEquals(newLocation, req.getUrl().toString());
}
@Deprecated
public void testExecuteErrorWithRetryEnabled() throws Exception {
int callsBeforeSuccess = 3;
FailThenSuccessConnectionErrorTransport fakeTransport =
new FailThenSuccessConnectionErrorTransport(callsBeforeSuccess);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setRetryOnExecuteIOException(true);
req.setNumberOfRetries(callsBeforeSuccess + 1);
HttpResponse resp = req.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(4, fakeTransport.lowLevelExecCalls);
}
public void testExecuteErrorWithIOExceptionHandler() throws Exception {
int callsBeforeSuccess = 3;
FailThenSuccessConnectionErrorTransport fakeTransport =
new FailThenSuccessConnectionErrorTransport(callsBeforeSuccess);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(BackOff.ZERO_BACKOFF));
req.setNumberOfRetries(callsBeforeSuccess + 1);
HttpResponse resp = req.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(4, fakeTransport.lowLevelExecCalls);
}
@Deprecated
public void testExecuteErrorWithRetryEnabledBeyondRetryLimit() throws Exception {
int callsBeforeSuccess = 11;
FailThenSuccessConnectionErrorTransport fakeTransport =
new FailThenSuccessConnectionErrorTransport(callsBeforeSuccess);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setRetryOnExecuteIOException(true);
req.setNumberOfRetries(callsBeforeSuccess - 1);
try {
req.execute();
fail("Expected: " + IOException.class);
} catch (IOException e) {
// Expected
}
Assert.assertEquals(callsBeforeSuccess, fakeTransport.lowLevelExecCalls);
}
public void testExecuteErrorWithIOExceptionHandlerBeyondRetryLimit() throws Exception {
int callsBeforeSuccess = 11;
FailThenSuccessConnectionErrorTransport fakeTransport =
new FailThenSuccessConnectionErrorTransport(callsBeforeSuccess);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(BackOff.ZERO_BACKOFF));
req.setNumberOfRetries(callsBeforeSuccess - 1);
try {
req.execute();
fail("Expected: " + IOException.class);
} catch (IOException e) {
// Expected
}
Assert.assertEquals(callsBeforeSuccess, fakeTransport.lowLevelExecCalls);
}
public void testExecuteErrorWithoutIOExceptionHandler() throws Exception {
int callsBeforeSuccess = 3;
FailThenSuccessConnectionErrorTransport fakeTransport =
new FailThenSuccessConnectionErrorTransport(callsBeforeSuccess);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
// I/O exception handler is null by default
req.setNumberOfRetries(callsBeforeSuccess + 1);
try {
req.execute();
fail("Expected: " + IOException.class);
} catch (IOException e) {
// Expected
}
Assert.assertEquals(1, fakeTransport.lowLevelExecCalls);
}
@Deprecated
public void testUserAgentWithExecuteErrorAndRetryEnabled() throws Exception {
int callsBeforeSuccess = 3;
FailThenSuccessConnectionErrorTransport fakeTransport =
new FailThenSuccessConnectionErrorTransport(callsBeforeSuccess);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setRetryOnExecuteIOException(true);
req.setNumberOfRetries(callsBeforeSuccess + 1);
HttpResponse resp = req.execute();
Assert.assertEquals(1, fakeTransport.userAgentHeader.size());
Assert.assertEquals(HttpRequest.USER_AGENT_SUFFIX, fakeTransport.userAgentHeader.get(0));
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(4, fakeTransport.lowLevelExecCalls);
}
public void testUserAgentWithExecuteErrorAndIOExceptionHandler() throws Exception {
int callsBeforeSuccess = 3;
FailThenSuccessConnectionErrorTransport fakeTransport =
new FailThenSuccessConnectionErrorTransport(callsBeforeSuccess);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(BackOff.ZERO_BACKOFF));
req.setNumberOfRetries(callsBeforeSuccess + 1);
HttpResponse resp = req.execute();
Assert.assertEquals(1, fakeTransport.userAgentHeader.size());
Assert.assertEquals(HttpRequest.USER_AGENT_SUFFIX, fakeTransport.userAgentHeader.get(0));
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(4, fakeTransport.lowLevelExecCalls);
}
public void testAbnormalResponseHandlerWithNoBackOff() throws Exception {
FailThenSuccessBackoffTransport fakeTransport =
new FailThenSuccessBackoffTransport(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED, 1);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(true);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setUnsuccessfulResponseHandler(handler);
HttpResponse resp = req.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
Assert.assertTrue(handler.isCalled());
}
@Deprecated
public void testAbnormalResponseHandlerWithBackOff() throws Exception {
FailThenSuccessBackoffTransport fakeTransport =
new FailThenSuccessBackoffTransport(HttpStatusCodes.STATUS_CODE_SERVER_ERROR, 1);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(true);
MockBackOffPolicy backOffPolicy = new MockBackOffPolicy();
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setUnsuccessfulResponseHandler(handler);
req.setBackOffPolicy(backOffPolicy);
HttpResponse resp = req.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(1, backOffPolicy.resetCalls);
Assert.assertEquals(0, backOffPolicy.backOffCalls);
Assert.assertTrue(handler.isCalled());
}
public void testAbnormalResponseHandlerWithBackOffUnsuccessfulResponseHandler() throws Exception {
FailThenSuccessBackoffTransport fakeTransport =
new FailThenSuccessBackoffTransport(HttpStatusCodes.STATUS_CODE_SERVER_ERROR, 1);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(true);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
MockBackOff backOff = new MockBackOff();
setBackOffUnsuccessfulResponseHandler(req, backOff, handler);
HttpResponse resp = req.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(0, backOff.getNumberOfTries());
Assert.assertTrue(handler.isCalled());
}
@Deprecated
public void testBackOffSingleCall() throws Exception {
FailThenSuccessBackoffTransport fakeTransport =
new FailThenSuccessBackoffTransport(HttpStatusCodes.STATUS_CODE_SERVER_ERROR, 1);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
MockBackOffPolicy backOffPolicy = new MockBackOffPolicy();
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setUnsuccessfulResponseHandler(handler);
req.setBackOffPolicy(backOffPolicy);
HttpResponse resp = req.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(1, backOffPolicy.resetCalls);
Assert.assertEquals(1, backOffPolicy.backOffCalls);
Assert.assertTrue(handler.isCalled());
}
public void testBackOffUnsuccessfulResponseSingleCall() throws Exception {
FailThenSuccessBackoffTransport fakeTransport =
new FailThenSuccessBackoffTransport(HttpStatusCodes.STATUS_CODE_SERVER_ERROR, 1);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
MockBackOff backOff = new MockBackOff();
setBackOffUnsuccessfulResponseHandler(req, backOff, handler);
HttpResponse resp = req.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(1, backOff.getNumberOfTries());
Assert.assertTrue(handler.isCalled());
}
@Deprecated
public void testBackOffMultipleCalls() throws Exception {
int callsBeforeSuccess = 5;
FailThenSuccessBackoffTransport fakeTransport = new FailThenSuccessBackoffTransport(
HttpStatusCodes.STATUS_CODE_SERVER_ERROR, callsBeforeSuccess);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
MockBackOffPolicy backOffPolicy = new MockBackOffPolicy();
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setUnsuccessfulResponseHandler(handler);
req.setBackOffPolicy(backOffPolicy);
HttpResponse resp = req.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(callsBeforeSuccess + 1, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(1, backOffPolicy.resetCalls);
Assert.assertEquals(callsBeforeSuccess, backOffPolicy.backOffCalls);
Assert.assertTrue(handler.isCalled());
}
public void testBackOffUnsucessfulReponseMultipleCalls() throws Exception {
int callsBeforeSuccess = 5;
FailThenSuccessBackoffTransport fakeTransport = new FailThenSuccessBackoffTransport(
HttpStatusCodes.STATUS_CODE_SERVER_ERROR, callsBeforeSuccess);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
MockBackOff backOff = new MockBackOff();
setBackOffUnsuccessfulResponseHandler(req, backOff, handler);
HttpResponse resp = req.execute();
Assert.assertEquals(200, resp.getStatusCode());
Assert.assertEquals(callsBeforeSuccess + 1, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(callsBeforeSuccess, backOff.getNumberOfTries());
Assert.assertTrue(handler.isCalled());
}
@Deprecated
public void testBackOffCallsBeyondRetryLimit() throws Exception {
int callsBeforeSuccess = 11;
FailThenSuccessBackoffTransport fakeTransport = new FailThenSuccessBackoffTransport(
HttpStatusCodes.STATUS_CODE_SERVER_ERROR, callsBeforeSuccess);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
MockBackOffPolicy backOffPolicy = new MockBackOffPolicy();
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setNumberOfRetries(callsBeforeSuccess - 1);
req.setUnsuccessfulResponseHandler(handler);
req.setBackOffPolicy(backOffPolicy);
try {
req.execute();
fail("expected HttpResponseException");
} catch (HttpResponseException e) {
}
Assert.assertEquals(callsBeforeSuccess, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(1, backOffPolicy.resetCalls);
Assert.assertEquals(callsBeforeSuccess - 1, backOffPolicy.backOffCalls);
Assert.assertTrue(handler.isCalled());
}
public void testBackOffUnsuccessfulReponseCallsBeyondRetryLimit() throws Exception {
int callsBeforeSuccess = 11;
FailThenSuccessBackoffTransport fakeTransport = new FailThenSuccessBackoffTransport(
HttpStatusCodes.STATUS_CODE_SERVER_ERROR, callsBeforeSuccess);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setNumberOfRetries(callsBeforeSuccess - 1);
MockBackOff backOff = new MockBackOff();
setBackOffUnsuccessfulResponseHandler(req, backOff, handler);
try {
req.execute();
fail("expected HttpResponseException");
} catch (HttpResponseException e) {
}
Assert.assertEquals(callsBeforeSuccess, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(callsBeforeSuccess - 1, backOff.getMaxTries());
Assert.assertTrue(handler.isCalled());
}
@Deprecated
public void testBackOffUnRecognizedStatusCode() throws Exception {
FailThenSuccessBackoffTransport fakeTransport =
new FailThenSuccessBackoffTransport(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED, 1);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
MockBackOffPolicy backOffPolicy = new MockBackOffPolicy();
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setUnsuccessfulResponseHandler(handler);
req.setBackOffPolicy(backOffPolicy);
try {
req.execute();
} catch (HttpResponseException e) {
}
Assert.assertEquals(1, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(1, backOffPolicy.resetCalls);
// The BackOffPolicy should not be called since it does not support 401 status codes.
Assert.assertEquals(0, backOffPolicy.backOffCalls);
Assert.assertTrue(handler.isCalled());
}
public void testBackOffUnsuccessfulReponseUnRecognizedStatusCode() throws Exception {
FailThenSuccessBackoffTransport fakeTransport =
new FailThenSuccessBackoffTransport(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED, 1);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
MockBackOff backOff = new MockBackOff();
setBackOffUnsuccessfulResponseHandler(req, backOff, handler);
try {
req.execute();
} catch (HttpResponseException e) {
}
Assert.assertEquals(1, fakeTransport.lowLevelExecCalls);
// The back-off should not be called since it does not support 401 status codes.
Assert.assertEquals(0, backOff.getNumberOfTries());
Assert.assertTrue(handler.isCalled());
}
@Deprecated
public void testBackOffStop() throws Exception {
int callsBeforeSuccess = 5;
FailThenSuccessBackoffTransport fakeTransport = new FailThenSuccessBackoffTransport(
HttpStatusCodes.STATUS_CODE_SERVER_ERROR, callsBeforeSuccess);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
MockBackOffPolicy backOffPolicy = new MockBackOffPolicy();
backOffPolicy.returnBackOffStop = true;
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
req.setUnsuccessfulResponseHandler(handler);
req.setBackOffPolicy(backOffPolicy);
try {
req.execute();
} catch (HttpResponseException e) {
}
Assert.assertEquals(1, fakeTransport.lowLevelExecCalls);
Assert.assertEquals(1, backOffPolicy.resetCalls);
// The BackOffPolicy should be called only once and then it should return BackOffPolicy.STOP
// should stop all back off retries.
Assert.assertEquals(1, backOffPolicy.backOffCalls);
Assert.assertTrue(handler.isCalled());
}
public void testBackOffUnsucessfulResponseStop() throws Exception {
int callsBeforeSuccess = 5;
FailThenSuccessBackoffTransport fakeTransport = new FailThenSuccessBackoffTransport(
HttpStatusCodes.STATUS_CODE_SERVER_ERROR, callsBeforeSuccess);
MockHttpUnsuccessfulResponseHandler handler = new MockHttpUnsuccessfulResponseHandler(false);
HttpRequest req =
fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used"));
MockBackOff backOff = new MockBackOff().setMaxTries(1);
setBackOffUnsuccessfulResponseHandler(req, backOff, handler);
try {
req.execute();
} catch (HttpResponseException e) {
}
Assert.assertEquals(2, fakeTransport.lowLevelExecCalls);
// The back-off should be called only once, since the its max tries is set to 1
Assert.assertEquals(1, backOff.getNumberOfTries());
Assert.assertTrue(handler.isCalled());
}
public enum E {
@Value
VALUE,
@Value("other")
OTHER_VALUE,
}
public static class MyHeaders extends HttpHeaders {
@Key
public String foo;
@Key
Object objNum;
@Key
Object objList;
@Key
List<String> list;
@Key
String[] r;
@Key
E value;
@Key
E otherValue;
}
public void testExecute_headerSerialization() throws Exception {
// custom headers
MyHeaders myHeaders = new MyHeaders();
myHeaders.foo = "bar";
myHeaders.objNum = 5;
myHeaders.list = ImmutableList.of("a", "b", "c");
myHeaders.objList = ImmutableList.of("a2", "b2", "c2");
myHeaders.r = new String[] {"a1", "a2"};
myHeaders.setAcceptEncoding(null);
myHeaders.setUserAgent("foo");
myHeaders.set("a", "b");
myHeaders.value = E.VALUE;
myHeaders.otherValue = E.OTHER_VALUE;
// execute request
final MockLowLevelHttpRequest lowLevelRequest = new MockLowLevelHttpRequest();
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return lowLevelRequest;
}
};
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
request.setHeaders(myHeaders);
request.execute();
// check headers
assertEquals(ImmutableList.of("bar"), lowLevelRequest.getHeaderValues("foo"));
assertEquals(ImmutableList.of("a", "b", "c"), lowLevelRequest.getHeaderValues("list"));
assertEquals(ImmutableList.of("a2", "b2", "c2"), lowLevelRequest.getHeaderValues("objlist"));
assertEquals(ImmutableList.of("a1", "a2"), lowLevelRequest.getHeaderValues("r"));
assertTrue(lowLevelRequest.getHeaderValues("accept-encoding").isEmpty());
assertEquals(ImmutableList.of("foo " + HttpRequest.USER_AGENT_SUFFIX),
lowLevelRequest.getHeaderValues("user-agent"));
assertEquals(ImmutableList.of("b"), lowLevelRequest.getHeaderValues("a"));
assertEquals(ImmutableList.of("VALUE"), lowLevelRequest.getHeaderValues("value"));
assertEquals(ImmutableList.of("other"), lowLevelRequest.getHeaderValues("othervalue"));
}
public void testGZipEncoding() throws Exception {
class MyTransport extends MockHttpTransport {
boolean expectGZip;
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
if (expectGZip) {
assertEquals(HttpEncodingStreamingContent.class, getStreamingContent().getClass());
assertEquals("gzip", getContentEncoding());
assertEquals(25, getContentLength());
} else {
assertFalse(
getStreamingContent().getClass().equals(HttpEncodingStreamingContent.class));
assertNull(getContentEncoding());
assertEquals(300, getContentLength());
}
char[] content = new char[300];
Arrays.fill(content, ' ');
assertEquals(new String(content), getContentAsString());
return super.execute();
}
};
}
}
MyTransport transport = new MyTransport();
byte[] content = new byte[300];
Arrays.fill(content, (byte) ' ');
HttpRequest request = transport.createRequestFactory().buildPostRequest(
HttpTesting.SIMPLE_GENERIC_URL, new ByteArrayContent(
new HttpMediaType("text/plain").setCharsetParameter(Charsets.UTF_8).build(), content));
assertNull(request.getEncoding());
request.execute();
assertNull(request.getEncoding());
request.execute();
request.setEncoding(new GZipEncoding());
transport.expectGZip = true;
request.execute();
}
public void testContentLoggingLimitWithLoggingEnabledAndDisabled() throws Exception {
class MyTransport extends MockHttpTransport {
boolean expectLogContent;
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
if (expectLogContent) {
assertEquals(LoggingStreamingContent.class, getStreamingContent().getClass());
} else {
assertEquals(ByteArrayContent.class, getStreamingContent().getClass());
}
return super.execute();
}
};
}
}
MyTransport transport = new MyTransport();
// Set the logging level.
HttpTransport.LOGGER.setLevel(java.util.logging.Level.CONFIG);
// Create content of length 300.
byte[] content = new byte[300];
Arrays.fill(content, (byte) ' ');
HttpRequest request = transport.createRequestFactory().buildPostRequest(
HttpTesting.SIMPLE_GENERIC_URL, new ByteArrayContent("text/html", content));
// Assert logging is enabled by default.
assertTrue(request.isLoggingEnabled());
// Set the content logging limit to be equal to the length of the content.
transport.expectLogContent = true;
request.setContentLoggingLimit(300);
request.execute();
// Set the content logging limit to be less than the length of the content.
transport.expectLogContent = true;
request.setContentLoggingLimit(299);
request.execute();
// Set the content logging limit to 0 to disable content logging.
transport.expectLogContent = true;
request.setContentLoggingLimit(0);
request.execute();
// Set the content logging limit to be equal to the length of the content with logging disabled.
transport.expectLogContent = false;
request.setContentLoggingLimit(300);
request.setLoggingEnabled(false);
request.execute();
// Assert that an exception is thrown if content logging limit < 0.
try {
request.setContentLoggingLimit(-1);
fail("Expected: " + IllegalArgumentException.class);
} catch (IllegalArgumentException e) {
// Expected
}
}
public void testUserAgent() {
assertTrue(HttpRequest.USER_AGENT_SUFFIX.contains("Google-HTTP-Java-Client"));
assertTrue(HttpRequest.USER_AGENT_SUFFIX.contains("gzip"));
}
public void testExecute_headers() throws Exception {
HttpTransport transport = new MockHttpTransport();
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
request.getHeaders().setAccept("*/*");
request.getHeaders().set("accept", Arrays.asList("text/plain"));
request.execute();
}
public void testSuppressUserAgentSuffix() throws Exception {
class MyTransport extends MockHttpTransport {
String expectedUserAgent;
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
assertEquals(expectedUserAgent, getFirstHeaderValue("User-Agent"));
return super.execute();
}
};
}
}
MyTransport transport = new MyTransport();
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
// Do not specify a User-Agent.
transport.expectedUserAgent = HttpRequest.USER_AGENT_SUFFIX;
request.setSuppressUserAgentSuffix(false);
request.execute();
// Do not specify a User-Agent.
transport.expectedUserAgent = null;
request.setSuppressUserAgentSuffix(true);
request.execute();
// Specify a User-Agent with suppress=false.
transport.expectedUserAgent = "Testing " + HttpRequest.USER_AGENT_SUFFIX;
request.getHeaders().setUserAgent("Testing");
request.setSuppressUserAgentSuffix(false);
request.execute();
// Specify a User-Agent with suppress=true.
transport.expectedUserAgent = "Testing";
request.getHeaders().setUserAgent("Testing");
request.setSuppressUserAgentSuffix(true);
request.execute();
}
public void testExecuteAsync()
throws IOException, InterruptedException, ExecutionException, TimeoutException {
MockExecutor mockExecutor = new MockExecutor();
HttpTransport transport = new MockHttpTransport();
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
Future<HttpResponse> futureResponse = request.executeAsync(mockExecutor);
assertFalse(futureResponse.isDone());
mockExecutor.actuallyRun();
assertTrue(futureResponse.isDone());
assertNotNull(futureResponse.get(10, TimeUnit.MILLISECONDS));
}
public void testExecute_redirects() throws Exception {
class MyTransport extends MockHttpTransport {
int count = 1;
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
// expect that it redirected to new URL every time using the count
assertEquals(HttpTesting.SIMPLE_URL + "_" + count, url);
count++;
return new MockLowLevelHttpRequest().setResponse(
new MockLowLevelHttpResponse().setStatusCode(
HttpStatusCodes.STATUS_CODE_MOVED_PERMANENTLY)
.setHeaderNames(Arrays.asList("Location"))
.setHeaderValues(Arrays.asList(HttpTesting.SIMPLE_URL + "_" + count)));
}
}
MyTransport transport = new MyTransport();
HttpRequest request = transport.createRequestFactory()
.buildGetRequest(new GenericUrl(HttpTesting.SIMPLE_URL + "_" + transport.count));
try {
request.execute();
fail("expected " + HttpResponseException.class);
} catch (HttpResponseException e) {
assertEquals(HttpStatusCodes.STATUS_CODE_MOVED_PERMANENTLY, e.getStatusCode());
}
}
public void testExecute_redirectWithIncorrectContentRetryableSetting() throws Exception {
// TODO(yanivi): any way we can warn user about this?
RedirectTransport fakeTransport = new RedirectTransport();
String contentValue = "hello";
fakeTransport.expectedContent = new String[] {contentValue, ""};
byte[] bytes = StringUtils.getBytesUtf8(contentValue);
InputStreamContent content = new InputStreamContent(
new HttpMediaType("text/plain").setCharsetParameter(Charsets.UTF_8).build(),
new ByteArrayInputStream(bytes));
content.setRetrySupported(true);
HttpRequest request = fakeTransport.createRequestFactory()
.buildPostRequest(HttpTesting.SIMPLE_GENERIC_URL, content);
HttpResponse resp = request.execute();
assertEquals(200, resp.getStatusCode());
assertEquals(2, fakeTransport.lowLevelExecCalls);
}
public void testExecute_curlLogger() throws Exception {
LogRecordingHandler recorder = new LogRecordingHandler();
HttpTransport.LOGGER.setLevel(Level.CONFIG);
HttpTransport.LOGGER.addHandler(recorder);
new MockHttpTransport().createRequestFactory()
.buildGetRequest(new GenericUrl("http://google.com/#q=a'b'c")).execute();
boolean found = false;
for (String message : recorder.messages()) {
if (message.startsWith("curl")) {
found = true;
assertEquals("curl -v --compressed -H 'Accept-Encoding: gzip' -H 'User-Agent: "
+ HttpRequest.USER_AGENT_SUFFIX + "' -- 'http://google.com/#q=a'\"'\"'b'\"'\"'c'",
message);
}
}
assertTrue(found);
}
public void testExecute_curlLoggerWithContentEncoding() throws Exception {
LogRecordingHandler recorder = new LogRecordingHandler();
HttpTransport.LOGGER.setLevel(Level.CONFIG);
HttpTransport.LOGGER.addHandler(recorder);
String contentValue = "hello";
byte[] bytes = StringUtils.getBytesUtf8(contentValue);
InputStreamContent content = new InputStreamContent(
new HttpMediaType("text/plain").setCharsetParameter(Charsets.UTF_8).build(),
new ByteArrayInputStream(bytes));
new MockHttpTransport().createRequestFactory()
.buildPostRequest(new GenericUrl("http://google.com/#q=a'b'c"), content)
.setEncoding(new GZipEncoding()).execute();
boolean found = false;
final String expectedCurlLog = "curl -v --compressed -X POST -H 'Accept-Encoding: gzip' "
+ "-H 'User-Agent: " + HttpRequest.USER_AGENT_SUFFIX
+ "' -H 'Content-Type: text/plain; charset=UTF-8' -H 'Content-Encoding: gzip' "
+ "-d '@-' -- 'http://google.com/#q=a'\"'\"'b'\"'\"'c' << $$$";
for (String message : recorder.messages()) {
if (message.startsWith("curl")) {
found = true;
assertEquals(expectedCurlLog, message);
}
}
assertTrue(found);
}
}