/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.cloud.platform.clientlib;
import java.io.IOException;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ClientHttpRequest {
private HttpClient httpClient;
private JAXBContext unmarshallingJaxbContext;
private JAXBContext marshallingJaxbContext;
public static final Logger log = LoggerFactory.getLogger(ClientHttpRequest.class);
@SuppressWarnings("unused")
private ClientHttpRequest() {
// NOP - use the factory
}
ClientHttpRequest(HttpClient httpClient, JAXBContext mjaxbContext, JAXBContext umjaxbContext) throws ClientGeneralException {
this.httpClient = httpClient;
this.marshallingJaxbContext = mjaxbContext;
this.unmarshallingJaxbContext = umjaxbContext;
if (this.httpClient == null) {
throw new IllegalArgumentException("request object requires a non-null httpClient");
}
if (this.marshallingJaxbContext == null) {
throw new IllegalArgumentException("request object requires a non-null marhsallingJaxbContext");
}
if (this.unmarshallingJaxbContext == null) {
throw new IllegalArgumentException("request object requires a non-null unmarshallingJaxbContext");
}
}
@Deprecated
public String httpGetString(String url) throws ClientGeneralException {
HttpGet get = new HttpGet(url);
get.setHeader("Content-Type", "application/json");
get.setHeader("ACCEPT", "application/json");
try {
String response = httpClient.execute(get, new StringHttpResponseHandler());
return response;
} catch (ClientProtocolException ex) {
throw new ClientGeneralException(ClientMessageKeys.CLIENT_PROTOCOL_EXCEPTION, ex);
} catch (IOException ex) {
throw new ClientGeneralException(ClientMessageKeys.IO_EXCEPTION, ex);
}
}
public Object httpGetXML(String url) throws ClientGeneralException {
HttpGet get = new HttpGet(url);
get.setHeader("Content-Type", "application/xml");
get.setHeader("ACCEPT", "application/xml");
log.debug("GET: " + url);
try {
Object response = httpClient.execute(get, new XMLHttpResponseHandler(unmarshallingJaxbContext, "GET " + url, ""));
return response;
} catch (ClientHttpResponseException ex) {
throw new ClientResponseException(ex);
} catch (ClientProtocolException ex) {
throw new ClientGeneralException(ClientMessageKeys.CLIENT_PROTOCOL_EXCEPTION, new String[] { ex.getMessage() }, ex);
} catch (IOException ex) {
throw new ClientGeneralException(ClientMessageKeys.IO_EXCEPTION, new String[] { ex.getMessage() }, ex);
}
}
public String httpGetObjectXML(String url) throws ClientGeneralException {
HttpGet get = new HttpGet(url);
get.setHeader("Content-Type", "application/xml");
get.setHeader("ACCEPT", "application/xml");
log.debug("GET: " + url);
try {
HttpResponse response = httpClient.execute(get);
return EntityUtils.toString(response.getEntity());
} catch (ClientHttpResponseException ex) {
throw getMaskedDetailClientGeneralException(ex);
} catch (ClientProtocolException ex) {
throw new ClientGeneralException(ClientMessageKeys.CLIENT_PROTOCOL_EXCEPTION, ex);
} catch (IOException ex) {
throw new ClientGeneralException(ClientMessageKeys.IO_EXCEPTION, ex);
}
}
public <T> T httpPostXMLObject(String url, JAXBElement<?> jaxbElement, Class<T> returnType) throws ClientGeneralException {
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/xml");
post.setHeader("ACCEPT", "application/xml");
log.debug("POST: " + url);
try {
StringWriter writer = new StringWriter();
if (jaxbElement != null) {
Marshaller marshaller = marshallingJaxbContext.createMarshaller();
marshaller.marshal(jaxbElement, writer);
}
String payload = writer.toString();
if (payload != null && payload.length() != 0) {
post.setEntity(new StringEntity(payload));
// log payloads at DEBUG level only because they may contain passwords
log.debug("Payload:\n" + maskPayloadCredentials(payload));
}
return httpClient.execute(post, new XMLHttpResponseHandler<T>(unmarshallingJaxbContext, "POST " + url,
payload != null ? payload.toString() : ""));
} catch (ClientHttpResponseException ex) {
throw getMaskedDetailClientGeneralException(ex);
} catch (ClientProtocolException ex) {
throw new ClientGeneralException(ClientMessageKeys.CLIENT_PROTOCOL_EXCEPTION, ex);
} catch (IOException ex) {
throw new ClientGeneralException(ClientMessageKeys.IO_EXCEPTION, ex);
} catch (JAXBException ex) {
throw new ClientGeneralException(ClientMessageKeys.MODEL_EXCEPTION, ex);
}
}
public Object httpPostXMLObject(String url) throws ClientGeneralException {
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/xml");
post.setHeader("ACCEPT", "application/xml");
log.debug("POST: " + url);
try {
Object response = httpClient.execute(post, new XMLHttpResponseHandler(unmarshallingJaxbContext, "POST " + url, ""));
return response;
} catch (ClientHttpResponseException ex) {
throw getMaskedDetailClientGeneralException(ex);
} catch (ClientProtocolException ex) {
throw new ClientGeneralException(ClientMessageKeys.CLIENT_PROTOCOL_EXCEPTION, ex);
} catch (IOException ex) {
throw new ClientGeneralException(ClientMessageKeys.IO_EXCEPTION, ex);
}
}
public Object httpPutXMLObject(String url, JAXBElement<?> jaxbElement) throws ClientGeneralException {
HttpPut post = new HttpPut(url);
post.setHeader("Content-Type", "application/xml");
post.setHeader("ACCEPT", "application/xml");
log.debug("PUT: " + url);
try {
Marshaller marshaller = marshallingJaxbContext.createMarshaller();
StringWriter writer = new StringWriter();
marshaller.marshal(jaxbElement, writer);
String payload = writer.toString();
if (payload != null && payload.length() != 0) {
post.setEntity(new StringEntity(payload));
// log payloads at DEBUG level only because they may contain passwords
log.debug("Payload:\n" + maskPayloadCredentials(payload));
}
Object response = httpClient.execute(post, new XMLHttpResponseHandler(unmarshallingJaxbContext, "PUT " + url,
payload != null ? payload.toString() : ""));
return response;
} catch (ClientHttpResponseException ex) {
throw getMaskedDetailClientGeneralException(ex);
} catch (ClientProtocolException ex) {
throw new ClientGeneralException(ClientMessageKeys.CLIENT_PROTOCOL_EXCEPTION, ex);
} catch (IOException ex) {
throw new ClientGeneralException(ClientMessageKeys.IO_EXCEPTION, ex);
} catch (JAXBException ex) {
throw new ClientGeneralException(ClientMessageKeys.MODEL_EXCEPTION, ex);
}
}
public Object httpDeleteXMLObject(String url) throws ClientGeneralException {
HttpDelete delete = new HttpDelete(url);
delete.setHeader("Content-Type", "application/xml");
delete.setHeader("ACCEPT", "application/xml");
log.debug("DELETE: " + url);
try {
Object response = httpClient.execute(delete, new XMLHttpResponseHandler(unmarshallingJaxbContext, "DELETE " + url, ""));
return response;
} catch (ClientHttpResponseException ex) {
throw getMaskedDetailClientGeneralException(ex);
} catch (ClientProtocolException ex) {
throw new ClientGeneralException(ClientMessageKeys.CLIENT_PROTOCOL_EXCEPTION, ex);
} catch (IOException ex) {
throw new ClientGeneralException(ClientMessageKeys.IO_EXCEPTION, ex);
}
}
private String maskPayloadCredentials(String protectPayload) {
/*
* Properties of the payload are pattern matched based on the below keywords
* And then masked beyond recognition. This is protect the passwords and session cookies
* from appearing in clear text.
*/
String maskProperties[] = new String[] { "inPassword", "inCookie", "cookie", "password", "Cookie", "Password" };
String pattern = "";
for (int index = 0; index < maskProperties.length; index++) {
if (index == 0) {
// start building the pattern.
pattern += "(";
}
pattern += maskProperties[index];
if (index == maskProperties.length - 1) {
// end the pattern.
pattern += ")\\S+(\\s|$)";
} else {
pattern += "|";
}
}
log.debug("Pattern for masking sensitive payload info {}", pattern);
return protectPayload.replaceAll(pattern, "$1=\"masked\"");
}
private ClientGeneralException getMaskedDetailClientGeneralException(ClientHttpResponseException ex) {
/*
* Returns a ClientGeneralException with masked details for a ClientHttpResponseException
*/
ClientMessageKeys key = null;
ClientGeneralException exception = null;
if (ex.bcode != null) {
try {
key = ClientMessageKeys.byErrorCode(Integer.parseInt(ex.bcode));
exception = new ClientGeneralException(key, ex);
} catch (NumberFormatException msg) {
log.error(maskPayloadCredentials(ex.getMessage()));
return new ClientGeneralException(ClientMessageKeys.UNEXPECTED_FAILURE);
} catch (Exception msg) {
log.error(maskPayloadCredentials(ex.getMessage()));
return new ClientResponseException(ex);
}
}
return exception;
}
}