package io.mangoo.test.utils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.mangoo.configuration.Config;
import io.mangoo.core.Application;
import io.mangoo.enums.ContentType;
import io.mangoo.enums.Default;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.Methods;
/**
*
* @author svenkubiak
*
*/
public class WebResponse {
private static final Logger LOG = LogManager.getLogger(WebResponse.class);
private final CookieStore cookieStore = new BasicCookieStore();
private final Map<String, String> headers = new HashMap<>(); //NOSONAR
private final MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
private String responseUrl;
private String responseUri;
private String responseRequestBody;
private String responseContent = "";
private HttpString responseMethod;
private HttpResponse httpResponse;
private ContentType responseContentType;
private HttpClientBuilder httpClientBuilder;
private List<NameValuePair> postParameter = new ArrayList<>();
private boolean responseDisbaleRedirects;
private boolean hasFileBody;
public WebResponse (String uri, HttpString method) {
this.responseUri = uri;
this.responseMethod = method;
init();
}
public WebResponse() {
init();
}
private void init () {
final Config config = Application.getInstance(Config.class);
multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
final String host = config.getConnectorHttpHost();
final int port = config.getConnectorHttpPort();
this.cookieStore.clear();
this.responseUrl = "http://" + host + ":" + port;
this.httpClientBuilder = HttpClientBuilder.create().setDefaultCookieStore(this.cookieStore);
}
/**
* Sets the ContentType of the request
*
* @param contentType The content type to use
* @return Response
*/
public WebResponse withContentType(ContentType contentType) {
Objects.requireNonNull(contentType, "contentType can not be null");
this.responseContentType = contentType;
return this;
}
/**
* Sets the RequestBody of the request
*
* @param requestBody The request body to use
* @return Response
*/
public WebResponse withRequestBody(String requestBody) {
this.responseRequestBody = requestBody;
return this;
}
/**
* Sets Post parameter to the request
*
* @param postParameter A list of post parameter
* @return Response
*/
public WebResponse withPostParameters(List<NameValuePair> postParameter) {
Objects.requireNonNull(postParameter, "postParameter can not be null");
this.postParameter = Collections.unmodifiableList(postParameter);
return this;
}
/**
* Disables redirects when the request is executed
*
* @param disableRedirects true or false
* @return Response
*/
public WebResponse withDisableRedirects(boolean disableRedirects) {
this.responseDisbaleRedirects = disableRedirects;
return this;
}
/**
* Enables the LaxRedirectsStragey allowing more methods to be redirected
*
* @return Response
*/
public WebResponse withLaxRedirectStrategy() {
this.httpClientBuilder.setRedirectStrategy(new LaxRedirectStrategy());
return this;
}
/**
* Sets the URI to be executed by the request
*
* @param uri The URI to call
* @return Response
*/
public WebResponse withUri(String uri) {
Objects.requireNonNull(uri, "uri can not be null");
this.responseUri = uri;
return this;
}
/**
* Adds a FileBody to the request
*
* @param name The the of the file body
* @param fileBody The file body
* @return Response
*/
public WebResponse withFileBody(String name, FileBody fileBody) {
Objects.requireNonNull(fileBody, "fileBody can not be null");
this.hasFileBody = true;
this.multipartEntityBuilder.addPart(name, fileBody);
return this;
}
/**
* Sets the HTTP method to execute the request with
*
* @param method The HTTP Method
* @return Response
*/
public WebResponse withMethod(HttpString method) {
Objects.requireNonNull(method, "method can not be null");
this.responseMethod = method;
return this;
}
/**
* Adds an additional header to the request
*
* @param name The name of the header
* @param value The value of the header
* @return Response
*/
public WebResponse withHeader(String name, String value) {
Objects.requireNonNull(name, "name can not be null");
Objects.requireNonNull(value, "value can not be null");
this.headers.put(name, value);
return this;
}
/**
* Adds an additional cookie to the request
*
* @param cookie The cookie of the header
* @return Response
*/
public WebResponse withCookie(Cookie cookie) {
Objects.requireNonNull(cookie, "cookie can not be null");
this.cookieStore.addCookie(cookie);
return this;
}
/**
* Sets Basic HTTP Authentication the the request
*
* @param username The username
* @param password The password
* @return Response
*/
public WebResponse withBasicauthentication(String username, String password) {
Objects.requireNonNull(username, "username can not be null");
Objects.requireNonNull(password, "password can not be null");
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
this.httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider).setDefaultCookieStore(this.cookieStore);
return this;
}
/**
* Execute the HTTP request
*
* @return Response
*/
public WebResponse execute() {
if ((Methods.GET).equals(this.responseMethod)) {
final HttpGet httpGet = new HttpGet(this.responseUrl + this.responseUri);
return doRequest(httpGet);
} else if ((Methods.POST).equals(this.responseMethod)) {
final HttpPost httpPost = new HttpPost(responseUrl + responseUri);
try {
if (this.hasFileBody) {
httpPost.setEntity(multipartEntityBuilder.build());
} else if (StringUtils.isNotBlank(this.responseRequestBody)) {
httpPost.setEntity(new StringEntity(this.responseRequestBody));
} else {
httpPost.setEntity(new UrlEncodedFormEntity(this.postParameter, Default.ENCODING.toString()));
}
} catch (final UnsupportedEncodingException e) {
LOG.error("Failed to create HttpPost request", e);
}
return doRequest(httpPost);
} else if ((Methods.PUT).equals(this.responseMethod)) {
final HttpPut httpPut = new HttpPut(responseUrl + responseUri);
try {
if (StringUtils.isNotBlank(this.responseRequestBody)) {
httpPut.setEntity(new StringEntity(this.responseRequestBody));
} else {
httpPut.setEntity(new UrlEncodedFormEntity(this.postParameter, Default.ENCODING.toString()));
}
} catch (final UnsupportedEncodingException e) {
LOG.error("Failed to create HttpPut request", e);
}
return doRequest(httpPut);
} else if ((Methods.DELETE).equals(this.responseMethod)) {
final HttpDelete httpDelete = new HttpDelete(this.responseUrl + this.responseUri);
return doRequest(httpDelete);
} else if ((Methods.HEAD).equals(this.responseMethod)) {
final HttpHead httpHead = new HttpHead(this.responseUrl + this.responseUri);
return doRequest(httpHead);
} else if ((Methods.OPTIONS).equals(this.responseMethod)) {
final HttpOptions httpOptions = new HttpOptions(this.responseUrl + this.responseUri);
return doRequest(httpOptions);
} else if ((Methods.PATCH).equals(this.responseMethod)) {
final HttpPatch httpPatch = new HttpPatch(this.responseUrl + this.responseUri);
try {
if (StringUtils.isNotBlank(this.responseRequestBody)) {
httpPatch.setEntity(new StringEntity(this.responseRequestBody));
} else {
httpPatch.setEntity(new UrlEncodedFormEntity(this.postParameter, Default.ENCODING.toString()));
}
} catch (final UnsupportedEncodingException e) {
LOG.error("Failed to create HttpPut request", e);
}
return doRequest(httpPatch);
}
return this;
}
/**
* Performs the actual HTTP request
*
* @param request The HTTP request
* @return Response
*/
private WebResponse doRequest(HttpUriRequest request) {
if (this.responseContentType != null) {
request.setHeader(Headers.CONTENT_TYPE_STRING, responseContentType.toString());
}
this.headers.entrySet().forEach(entry -> request.setHeader(entry.getKey(), entry.getValue())); //NOSONAR
if (this.responseDisbaleRedirects) {
this.httpClientBuilder.disableRedirectHandling();
}
try {
this.httpResponse = this.httpClientBuilder.build().execute(request);
final HttpEntity httpEntity = this.httpResponse.getEntity();
if (httpEntity != null) {
this.responseContent = EntityUtils.toString(httpEntity);
}
} catch (final IOException e) {
LOG.error("Failed to execute request to " + responseUrl, e);
}
return this;
}
/**
* @return The response content
*/
public String getContent() {
return this.responseContent;
}
/**
* @return The HTTP response object
*/
public HttpResponse getHttpResponse() {
return this.httpResponse;
}
/**
* @return The status code of the response
*/
public int getStatusCode() {
return this.httpResponse.getStatusLine().getStatusCode();
}
/**
* Retrieves a specific header with the given name
*
* @param name The name of the header
* @return The value of the header or null if not found
*/
public String getHeader(String name) {
return (this.httpResponse.getFirstHeader(name) == null ) ? null : this.httpResponse.getFirstHeader(name).getValue();
}
/**
* @return The response cookie or an empty list
*/
public List<Cookie> getCookies() {
return this.cookieStore.getCookies();
}
/**
* Retrieves the cookie from the cookie store with a given name
*
* @param name The name of the cookie
* @return A Cookie or null if non found by name
*/
public Cookie getCookie(String name) {
for (final Cookie cookie : this.cookieStore.getCookies()) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}
/**
* @return The content type of the response
*/
public String getContentType() {
return this.httpResponse.getEntity().getContentType().getValue();
}
/**
* @return The response URL
*/
public String getResponseUrl() {
return responseUrl;
}
}