/*
* eXist Open Source Native XML Database
* Copyright (C) 2007-2009 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Id$
*/
package org.exist.xquery.modules.httpclient;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.xquery.AbstractInternalModule;
import org.exist.xquery.FunctionDef;
/**
* HTTPClient module
*
* @author Adam Retter <adam.retter@devon.gov.uk>
* @author Andrzej Taramina <andrzej@chaeron.com>
* @author ljo
* @version 1.3
* @serial 20100228
*/
public class HTTPClientModule extends AbstractInternalModule
{
private final static Logger LOG = LogManager.getLogger(HTTPClientModule.class);
public final static String NAMESPACE_URI = "http://exist-db.org/xquery/httpclient";
public final static String PREFIX = "httpclient";
public final static String INCLUSION_DATE = "2007-09-06";
public final static String RELEASED_IN_VERSION = "eXist-1.2";
public final static String HTTP_MODULE_PERSISTENT_STATE = "_eXist_httpclient_module_persistent_state";
public final static String HTTP_MODULE_PERSISTENT_OPTIONS = "_eXist_httpclient_module_persistent_options";
final static HttpClient httpClient = setupHttpClient();
private final static FunctionDef[] functions = {
new FunctionDef( GETFunction.signatures[0], GETFunction.class ),
new FunctionDef( GETFunction.signatures[1], GETFunction.class ),
new FunctionDef( PUTFunction.signatures[0], PUTFunction.class ),
new FunctionDef( PUTFunction.signatures[1], PUTFunction.class ),
new FunctionDef( DELETEFunction.signature, DELETEFunction.class ),
new FunctionDef( POSTFunction.signatures[0], POSTFunction.class ),
new FunctionDef( POSTFunction.signatures[1], POSTFunction.class ),
new FunctionDef( HEADFunction.signature, HEADFunction.class ),
new FunctionDef( OPTIONSFunction.signature, OPTIONSFunction.class ),
new FunctionDef( ClearFunction.signatures[0], ClearFunction.class ),
new FunctionDef( SetOptionsFunction.signatures[0], SetOptionsFunction.class)
};
public HTTPClientModule(Map<String, List<? extends Object>> parameters)
{
super( functions, parameters );
}
public String getNamespaceURI()
{
return( NAMESPACE_URI );
}
public String getDefaultPrefix()
{
return( PREFIX );
}
public String getDescription()
{
return( "A module for performing HTTP requests as a client" );
}
public String getReleaseVersion()
{
return( RELEASED_IN_VERSION );
}
private static HttpClient setupHttpClient() {
final HttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
final HttpClient client = new HttpClient(httpConnectionManager);
//config from file if present
final String configFile = System.getProperty("http.configfile");
if(configFile != null) {
final Path f = Paths.get(configFile);
if(Files.exists(f)) {
setConfigFromFile(f, client);
} else {
LOG.warn("http.configfile '" + f.toAbsolutePath() + "' does not exist!");
}
}
// Legacy: set the proxy server (if any) from system properties
final String proxyHost = System.getProperty("http.proxyHost");
if(proxyHost != null) {
//TODO: support for http.nonProxyHosts e.g. -Dhttp.nonProxyHosts="*.devonline.gov.uk|*.devon.gov.uk"
final ProxyHost proxy = new ProxyHost(proxyHost, Integer.parseInt(System.getProperty("http.proxyPort")));
client.getHostConfiguration().setProxyHost(proxy);
}
return client;
}
private static void setConfigFromFile(final Path configFile, final HttpClient http) {
if(LOG.isDebugEnabled()) {
LOG.debug("http.configfile='" + configFile.toAbsolutePath() + "'");
}
final Properties props = new Properties();
try(final InputStream is = Files.newInputStream(configFile)) {
if(LOG.isDebugEnabled()) {
LOG.debug("Loading proxy settings from " + configFile.toAbsolutePath());
}
props.load(is);
// Hostname / port
final String proxyHost = props.getProperty("proxy.host");
final int proxyPort = Integer.parseInt(props.getProperty("proxy.port", "8080"));
// Username / password
final String proxyUser = props.getProperty("proxy.user");
final String proxyPassword = props.getProperty("proxy.password");
// NTLM specifics
String proxyDomain = props.getProperty("proxy.ntlm.domain");
if ("NONE".equalsIgnoreCase(proxyDomain)) {
if(LOG.isDebugEnabled()) {
LOG.debug("Forcing removal NTLM");
}
proxyDomain = null;
}
// Set scope
final AuthScope authScope = new AuthScope(proxyHost, proxyPort);
// Setup right credentials
final Credentials credentials;
if (proxyDomain == null) {
credentials = new UsernamePasswordCredentials(proxyUser, proxyPassword);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Using NTLM authentication for '" + proxyDomain + "'");
}
credentials = new NTCredentials(proxyUser, proxyPassword, proxyHost, proxyDomain);
}
// Set details
final HttpState state = http.getState();
http.getHostConfiguration().setProxy(proxyHost, proxyPort);
state.setProxyCredentials(authScope, credentials);
if (LOG.isDebugEnabled()) {
LOG.info("Set proxy: " + proxyUser + "@" + proxyHost + ":"
+ proxyPort + (proxyDomain == null ? "" : " (NTLM:'"
+ proxyDomain + "')"));
}
} catch (final IOException ex) {
LOG.error("Failed to read proxy configuration from '" + configFile + "'");
}
}
}