
org.restcomm.connect.http.client.Downloader Maven / Gradle / Ivy
/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2014, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
*
*/
package org.restcomm.connect.http.client;
import akka.actor.ActorRef;
import akka.actor.UntypedActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
import org.restcomm.connect.commons.common.http.CustomHttpClientBuilder;
import org.restcomm.connect.commons.util.StringUtils;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLStreamException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
/**
* @author [email protected] (Thomas Quintana)
*/
public final class Downloader extends UntypedActor {
// Logger.
private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this);
public Downloader() {
super();
}
public HttpResponseDescriptor fetch(final HttpRequestDescriptor descriptor) throws IllegalArgumentException, IOException,
URISyntaxException, XMLStreamException {
int code = -1;
HttpRequest request = null;
CloseableHttpResponse response = null;
HttpRequestDescriptor temp = descriptor;
CloseableHttpClient client = null;
HttpResponseDescriptor responseDescriptor = null;
try {
do {
client = (CloseableHttpClient) CustomHttpClientBuilder.build(RestcommConfiguration.getInstance().getMain());
// client.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
// client.getParams().setParameter("http.protocol.content-charset", "UTF-8");
request = request(temp);
request.setHeader("http.protocol.content-charset", "UTF-8");
response = client.execute((HttpUriRequest) request);
code = response.getStatusLine().getStatusCode();
if (isRedirect(code)) {
final Header header = response.getFirstHeader(HttpHeaders.LOCATION);
if (header != null) {
final String location = header.getValue();
final URI uri = URI.create(location);
temp = new HttpRequestDescriptor(uri, temp.getMethod(), temp.getParameters());
continue;
} else {
break;
}
}
// HttpResponseDescriptor httpResponseDescriptor = response(request, response);
responseDescriptor = validateXML(response(request, response));
} while (isRedirect(code));
if (isHttpError(code)) {
String requestUrl = request.getRequestLine().getUri();
String errorReason = response.getStatusLine().getReasonPhrase();
String httpErrorMessage = String.format(
"Problem while fetching http resource: %s \n Http status code: %d \n Http status message: %s", requestUrl,
code, errorReason);
logger.warning(httpErrorMessage);
}
} catch (IllegalArgumentException | URISyntaxException | IOException e) {
if(logger.isDebugEnabled()){
// https://github.com/RestComm/Restcomm-Connect/issues/1419 Moving to DEBUG level to avoid polluting the logs
logger.debug("Issue during HTTP request execution: "+e.getCause());
}
HttpClientUtils.closeQuietly(client);
client = null;
} finally {
response.close();
HttpClientUtils.closeQuietly(client);
client = null;
}
return responseDescriptor;
}
private boolean isRedirect(final int code) {
return HttpStatus.SC_MOVED_PERMANENTLY == code || HttpStatus.SC_MOVED_TEMPORARILY == code
|| HttpStatus.SC_SEE_OTHER == code || HttpStatus.SC_TEMPORARY_REDIRECT == code;
}
private boolean isHttpError(final int code) {
return (code >= 400);
}
private HttpResponseDescriptor validateXML (final HttpResponseDescriptor descriptor) throws XMLStreamException {
if (descriptor.getContentLength() > 0) {
try {
// parse an XML document into a DOM tree
String xml = descriptor.getContentAsString().trim().replaceAll("&([^;]+(?!(?:\\w|;)))", "&$1");
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
parser.parse(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8"))));
return descriptor;
} catch (final Exception e) {
throw new XMLStreamException("Error parsing the RCML:" + e);
}
}
return descriptor;
}
@Override
public void onReceive(final Object message) throws Exception {
final Class> klass = message.getClass();
final ActorRef self = self();
final ActorRef sender = sender();
if (HttpRequestDescriptor.class.equals(klass)) {
final HttpRequestDescriptor request = (HttpRequestDescriptor) message;
if(logger.isDebugEnabled()){
logger.debug("New HttpRequestDescriptor, method: "+request.getMethod()+" URI: "+request.getUri()+" parameters: "+request.getParametersAsString());
}
DownloaderResponse response = null;
try {
response = new DownloaderResponse(fetch(request));
} catch (final Exception exception) {
logger.error("Exception while trying to download RCML ", exception);
response = new DownloaderResponse(exception, "Exception while trying to download RCML");
}
if (sender != null && !sender.isTerminated()) {
sender.tell(response, self);
} else {
if (logger.isInfoEnabled()) {
logger.info("DownloaderResponse wont be send because sender is :"+ (sender.isTerminated() ? "terminated" : "null"));
}
}
}
}
public HttpUriRequest request(final HttpRequestDescriptor descriptor) throws IllegalArgumentException, URISyntaxException,
UnsupportedEncodingException {
final URI uri = descriptor.getUri();
final String method = descriptor.getMethod();
if ("GET".equalsIgnoreCase(method)) {
final String query = descriptor.getParametersAsString();
URI result = null;
if (query != null && !query.isEmpty()) {
result = new URIBuilder()
.setScheme(uri.getScheme())
.setHost(uri.getHost())
.setPort(uri.getPort())
.setPath(uri.getPath())
.setQuery(query)
.build();
} else {
result = uri;
}
return new HttpGet(result);
} else if ("POST".equalsIgnoreCase(method)) {
final List parameters = descriptor.getParameters();
final HttpPost post = new HttpPost(uri);
post.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8"));
return post;
} else {
throw new IllegalArgumentException(method + " is not a supported downloader method.");
}
}
private HttpResponseDescriptor response(final HttpRequest request, final HttpResponse response) throws IOException {
final HttpResponseDescriptor.Builder builder = HttpResponseDescriptor.builder();
final URI uri = URI.create(request.getRequestLine().getUri());
builder.setURI(uri);
builder.setStatusCode(response.getStatusLine().getStatusCode());
builder.setStatusDescription(response.getStatusLine().getReasonPhrase());
builder.setHeaders(response.getAllHeaders());
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream stream = entity.getContent();
try {
final Header contentEncoding = entity.getContentEncoding();
if (contentEncoding != null) {
builder.setContentEncoding(contentEncoding.getValue());
}
final Header contentType = entity.getContentType();
if (contentType != null) {
builder.setContentType(contentType.getValue());
}
builder.setContent(StringUtils.toString(stream));
builder.setContentLength(entity.getContentLength());
builder.setIsChunked(entity.isChunked());
} finally {
stream.close();
}
}
return builder.build();
}
@Override
public void postStop() {
if(logger.isDebugEnabled()){
logger.debug("Downloader at post stop");
}
super.postStop();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy