com.google.api.client.http.HttpRequest Maven / Gradle / Ivy
Show all versions of google-api-client Show documentation
/*
* 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.repackaged.com.google.common.base.Preconditions;
import com.google.api.client.util.Strings;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* HTTP request.
*
* @since 1.0
* @author Yaniv Inbar
*/
public final class HttpRequest {
/** User agent suffix for all requests. */
private static final String USER_AGENT_SUFFIX =
"Google-API-Java-Client/1.1.1-alpha";
/**
* HTTP request headers.
*
* Its value is initialized by calling {@code clone()} on the
* {@link HttpTransport#defaultHeaders}. Therefore, it is initialized to be of
* the same Java class, i.e. of the same {@link Object#getClass()}.
*/
public HttpHeaders headers;
/**
* Whether to disable request content logging during {@link #execute()}
* (unless {@link Level#ALL} is loggable which forces all logging).
*
* Useful for example if content has sensitive data such as an authentication
* information. Defaults to {@code false}.
*/
public boolean disableContentLogging;
/** HTTP request content or {@code null} for none. */
public HttpContent content;
/** HTTP transport. */
public final HttpTransport transport;
/** HTTP request method. */
public String method;
// TODO: support more HTTP methods?
/** HTTP request URL. */
public GenericUrl url;
/**
* @param transport HTTP transport
* @param method HTTP request method (may be {@code null}
*/
HttpRequest(HttpTransport transport, String method) {
this.transport = transport;
this.headers = transport.defaultHeaders.clone();
this.method = method;
}
/** Sets the {@link #url} based on the given encoded URL string. */
public void setUrl(String encodedUrl) {
this.url = new GenericUrl(encodedUrl);
}
/**
* Execute the HTTP request and returns the HTTP response.
*
* Note that regardless of the returned status code, the HTTP response content
* has not been parsed yet, and must be parsed by the calling code.
*
* Almost all details of the request and response are logged if
* {@link Level#CONFIG} is loggable. The only exception is the value of the
* {@code Authorization} header which is only logged if {@link Level#ALL} is
* loggable.
*
* @return HTTP response for an HTTP success code
* @throws HttpResponseException for an HTTP error code
* @see HttpResponse#isSuccessStatusCode
*/
public HttpResponse execute() throws IOException {
Preconditions.checkNotNull(method);
Preconditions.checkNotNull(url);
HttpTransport transport = this.transport;
// first run the execute intercepters
for (HttpExecuteIntercepter intercepter : transport.intercepters) {
intercepter.intercept(this);
}
// build low-level HTTP request
LowLevelHttpTransport lowLevelHttpTransport =
HttpTransport.useLowLevelHttpTransport();
String method = this.method;
GenericUrl url = this.url;
String urlString = url.build();
LowLevelHttpRequest lowLevelHttpRequest;
if (method.equals("DELETE")) {
lowLevelHttpRequest = lowLevelHttpTransport.buildDeleteRequest(urlString);
} else if (method.equals("GET")) {
lowLevelHttpRequest = lowLevelHttpTransport.buildGetRequest(urlString);
} else if (method.equals("PATCH")) {
if (!lowLevelHttpTransport.supportsPatch()) {
throw new IllegalArgumentException(
"HTTP transport doesn't support PATCH");
}
lowLevelHttpRequest = lowLevelHttpTransport.buildPatchRequest(urlString);
} else if (method.equals("POST")) {
lowLevelHttpRequest = lowLevelHttpTransport.buildPostRequest(urlString);
} else if (method.equals("PUT")) {
lowLevelHttpRequest = lowLevelHttpTransport.buildPutRequest(urlString);
} else {
throw new IllegalArgumentException("illegal method: " + method);
}
Logger logger = HttpTransport.LOGGER;
boolean loggable = logger.isLoggable(Level.CONFIG);
StringBuilder logbuf = null;
// log method and URL
if (loggable) {
logbuf = new StringBuilder();
logbuf.append("-------------- REQUEST --------------").append(
Strings.LINE_SEPARATOR);
logbuf.append(method).append(' ').append(urlString).append(
Strings.LINE_SEPARATOR);
}
// add to user agent
HttpHeaders headers = this.headers;
if (headers.userAgent == null) {
headers.userAgent = USER_AGENT_SUFFIX;
} else {
headers.userAgent += " " + USER_AGENT_SUFFIX;
}
// headers
HashSet headerNames = new HashSet();
for (Map.Entry headerEntry : this.headers.entrySet()) {
String name = headerEntry.getKey();
String lowerCase = name.toLowerCase();
if (!headerNames.add(lowerCase)) {
throw new IllegalArgumentException(
"multiple headers of the same name (headers are case insensitive): "
+ lowerCase);
}
Object value = headerEntry.getValue();
if (value != null) {
if (value instanceof Collection>) {
for (Object repeatedValue : (Collection>) value) {
addHeader(logger, logbuf, lowLevelHttpRequest, name, repeatedValue);
}
} else {
addHeader(logger, logbuf, lowLevelHttpRequest, name, value);
}
}
}
// content
HttpContent content = this.content;
if (content != null) {
// check if possible to log content or gzip content
String contentEncoding = content.getEncoding();
long contentLength = content.getLength();
String contentType = content.getType();
if (contentLength != 0 && contentEncoding == null && contentType != null
&& LogContent.isTextBasedContentType(contentType)) {
// log content?
if (loggable && !this.disableContentLogging
|| logger.isLoggable(Level.ALL)) {
content = new LogContent(
content, contentType, contentEncoding, contentLength);
}
// gzip?
if (contentLength >= 256) {
content = new GZipContent(content, contentType);
contentEncoding = content.getEncoding();
contentLength = content.getLength();
}
}
// append content headers to log buffer
if (loggable) {
logbuf.append("Content-Type: " + contentType).append(
Strings.LINE_SEPARATOR);
if (contentEncoding != null) {
logbuf.append("Content-Encoding: " + contentEncoding).append(
Strings.LINE_SEPARATOR);
}
if (contentLength >= 0) {
logbuf.append("Content-Length: " + contentLength).append(
Strings.LINE_SEPARATOR);
}
}
lowLevelHttpRequest.setContent(content);
}
// log from buffer
if (loggable) {
logger.config(logbuf.toString());
}
// execute
HttpResponse response =
new HttpResponse(transport, lowLevelHttpRequest.execute());
if (!response.isSuccessStatusCode) {
throw new HttpResponseException(response);
}
return response;
}
private static void addHeader(Logger logger, StringBuilder logbuf,
LowLevelHttpRequest lowLevelHttpRequest, String name, Object value) {
String stringValue = value.toString();
if (logbuf != null) {
logbuf.append(name).append(": ");
if ("Authorization".equals(name) && !logger.isLoggable(Level.ALL)) {
logbuf.append("");
} else {
logbuf.append(stringValue);
}
logbuf.append(Strings.LINE_SEPARATOR);
}
lowLevelHttpRequest.addHeader(name, stringValue);
}
}