in google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java [834:1067]
public HttpResponse execute() throws IOException {
boolean retryRequest = false;
Preconditions.checkArgument(numRetries >= 0);
int retriesRemaining = numRetries;
if (backOffPolicy != null) {
// Reset the BackOffPolicy at the start of each execute.
backOffPolicy.reset();
}
HttpResponse response = null;
IOException executeException;
Preconditions.checkNotNull(requestMethod);
Preconditions.checkNotNull(url);
do {
// Cleanup any unneeded response from a previous iteration
if (response != null) {
response.ignore();
}
response = null;
executeException = null;
// run the interceptor
if (executeInterceptor != null) {
executeInterceptor.intercept(this);
}
// build low-level HTTP request
String urlString = url.build();
LowLevelHttpRequest lowLevelHttpRequest = transport.buildRequest(requestMethod, urlString);
Logger logger = HttpTransport.LOGGER;
boolean loggable = loggingEnabled && logger.isLoggable(Level.CONFIG);
StringBuilder logbuf = null;
StringBuilder curlbuf = null;
// log method and URL
if (loggable) {
logbuf = new StringBuilder();
logbuf.append("-------------- REQUEST --------------").append(StringUtils.LINE_SEPARATOR);
logbuf.append(requestMethod)
.append(' ').append(urlString).append(StringUtils.LINE_SEPARATOR);
// setup curl logging
if (curlLoggingEnabled) {
curlbuf = new StringBuilder("curl -v --compressed");
if (!requestMethod.equals(HttpMethods.GET)) {
curlbuf.append(" -X ").append(requestMethod);
}
}
}
// add to user agent
String originalUserAgent = headers.getUserAgent();
if (!suppressUserAgentSuffix) {
if (originalUserAgent == null) {
headers.setUserAgent(USER_AGENT_SUFFIX);
} else {
headers.setUserAgent(originalUserAgent + " " + USER_AGENT_SUFFIX);
}
}
// headers
HttpHeaders.serializeHeaders(headers, logbuf, curlbuf, logger, lowLevelHttpRequest);
if (!suppressUserAgentSuffix) {
// set the original user agent back so that retries do not keep appending to it
headers.setUserAgent(originalUserAgent);
}
// content
StreamingContent streamingContent = content;
final boolean contentRetrySupported = streamingContent == null || content.retrySupported();
if (streamingContent != null) {
final String contentEncoding;
final long contentLength;
final String contentType = content.getType();
// log content
if (loggable) {
streamingContent = new LoggingStreamingContent(
streamingContent, HttpTransport.LOGGER, Level.CONFIG, contentLoggingLimit);
}
// encoding
if (encoding == null) {
contentEncoding = null;
contentLength = content.getLength();
} else {
contentEncoding = encoding.getName();
streamingContent = new HttpEncodingStreamingContent(streamingContent, encoding);
contentLength = contentRetrySupported ? IOUtils.computeLength(streamingContent) : -1;
}
// append content headers to log buffer
if (loggable) {
if (contentType != null) {
String header = "Content-Type: " + contentType;
logbuf.append(header).append(StringUtils.LINE_SEPARATOR);
if (curlbuf != null) {
curlbuf.append(" -H '" + header + "'");
}
}
if (contentEncoding != null) {
String header = "Content-Encoding: " + contentEncoding;
logbuf.append(header).append(StringUtils.LINE_SEPARATOR);
if (curlbuf != null) {
curlbuf.append(" -H '" + header + "'");
}
}
if (contentLength >= 0) {
String header = "Content-Length: " + contentLength;
logbuf.append(header).append(StringUtils.LINE_SEPARATOR);
// do not log @ curl as the user will most likely manipulate the content
}
}
if (curlbuf != null) {
curlbuf.append(" -d '@-'");
}
// send content information to low-level HTTP request
lowLevelHttpRequest.setContentType(contentType);
lowLevelHttpRequest.setContentEncoding(contentEncoding);
lowLevelHttpRequest.setContentLength(contentLength);
lowLevelHttpRequest.setStreamingContent(streamingContent);
}
// log from buffer
if (loggable) {
logger.config(logbuf.toString());
if (curlbuf != null) {
curlbuf.append(" -- '");
curlbuf.append(urlString.replaceAll("\'", "'\"'\"'"));
curlbuf.append("'");
if (streamingContent != null) {
curlbuf.append(" << $$$");
}
logger.config(curlbuf.toString());
}
}
// We need to make sure our content type can support retry
// null content is inherently able to be retried
retryRequest = contentRetrySupported && retriesRemaining > 0;
// execute
lowLevelHttpRequest.setTimeout(connectTimeout, readTimeout);
try {
LowLevelHttpResponse lowLevelHttpResponse = lowLevelHttpRequest.execute();
// Flag used to indicate if an exception is thrown before the response is constructed.
boolean responseConstructed = false;
try {
response = new HttpResponse(this, lowLevelHttpResponse);
responseConstructed = true;
} finally {
if (!responseConstructed) {
InputStream lowLevelContent = lowLevelHttpResponse.getContent();
if (lowLevelContent != null) {
lowLevelContent.close();
}
}
}
} catch (IOException e) {
if (!retryOnExecuteIOException && (ioExceptionHandler == null
|| !ioExceptionHandler.handleIOException(this, retryRequest))) {
throw e;
}
// Save the exception in case the retries do not work and we need to re-throw it later.
executeException = e;
logger.log(Level.WARNING, "exception thrown while executing request", e);
}
// Flag used to indicate if an exception is thrown before the response has completed
// processing.
boolean responseProcessed = false;
try {
if (response != null && !response.isSuccessStatusCode()) {
boolean errorHandled = false;
if (unsuccessfulResponseHandler != null) {
// Even if we don't have the potential to retry, we might want to run the
// handler to fix conditions (like expired tokens) that might cause us
// trouble on our next request
errorHandled = unsuccessfulResponseHandler.handleResponse(this, response, retryRequest);
}
if (!errorHandled) {
if (handleRedirect(response.getStatusCode(), response.getHeaders())) {
// The unsuccessful request's error could not be handled and it is a redirect request.
errorHandled = true;
} else if (retryRequest && backOffPolicy != null
&& backOffPolicy.isBackOffRequired(response.getStatusCode())) {
// The unsuccessful request's error could not be handled and should be backed off
// before retrying
long backOffTime = backOffPolicy.getNextBackOffMillis();
if (backOffTime != BackOffPolicy.STOP) {
try {
sleeper.sleep(backOffTime);
} catch (InterruptedException exception) {
// ignore
}
errorHandled = true;
}
}
}
// A retry is required if the error was successfully handled or if it is a redirect
// request or if the back off policy determined a retry is necessary.
retryRequest &= errorHandled;
// need to close the response stream before retrying a request
if (retryRequest) {
response.ignore();
}
} else {
// Retry is not required for a successful status code unless the response is null.
retryRequest &= (response == null);
}
// Once there are no more retries remaining, this will be -1
// Count redirects as retries, we want a finite limit of redirects.
retriesRemaining--;
responseProcessed = true;
} finally {
if (response != null && !responseProcessed) {
response.disconnect();
}
}
} while (retryRequest);
if (response == null) {
// Retries did not help resolve the execute exception, re-throw it.
throw executeException;
}
// response interceptor
if (responseInterceptor != null) {
responseInterceptor.interceptResponse(response);
}
// throw an exception if unsuccessful response
if (throwExceptionOnExecuteError && !response.isSuccessStatusCode()) {
try {
throw new HttpResponseException(response);
} finally {
response.disconnect();
}
}
return response;
}