/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* 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 org.pentaho.di.cluster;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.lang.StringUtils;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.encryption.Encr;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.variables.VariableSpace;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class HttpUtil {
public static final int ZIP_BUFFER_SIZE = 8192;
private static final String PROTOCOL_UNSECURE = "http";
private static final String PROTOCOL_SECURE = "https";
private static HttpClient getClient( VariableSpace space, String hostname, String port, String webAppName,
String username, String password, String proxyHostname, String proxyPort, String nonProxyHosts ) {
HttpClient client = SlaveConnectionManager.getInstance().createHttpClient();
addCredentials( client, space, hostname, port, webAppName, username, password );
addProxy( client, space, hostname, proxyHostname, proxyPort, nonProxyHosts );
return client;
}
public static PostMethod execService( VariableSpace space, String hostname, String port, String webAppName,
String urlString, String username, String password, String proxyHostname, String proxyPort,
String nonProxyHosts, Iterable<Header> headers, Map<String, Object> parameters, Map<String, String> arguments )
throws Exception {
HttpClient
client =
getClient( space, hostname, port, webAppName, username, password, proxyHostname, proxyPort, nonProxyHosts );
client.getHttpConnectionManager().getParams().setConnectionTimeout( 0 );
client.getHttpConnectionManager().getParams().setSoTimeout( 0 );
PostMethod method = new PostMethod( urlString );
method.setDoAuthentication( true );
for ( Header header : headers ) {
method.addRequestHeader( header );
}
for ( Map.Entry<String, Object> parameter : parameters.entrySet() ) {
method.getParams().setParameter( parameter.getKey(), parameter.getValue() );
}
for ( Map.Entry<String, String> arg : arguments.entrySet() ) {
method.addParameter( arg.getKey(), arg.getValue() );
}
execMethod( client, method );
return method;
}
public static String execService( VariableSpace space, String hostname, String port, String webAppName,
String serviceAndArguments, String username, String password, String proxyHostname, String proxyPort,
String nonProxyHosts, boolean isSecure ) throws Exception {
HttpClient
client =
getClient( space, hostname, port, webAppName, username, password, proxyHostname, proxyPort, nonProxyHosts );
String urlString = constructUrl( space, hostname, port, webAppName, serviceAndArguments, isSecure );
HttpMethod method = new GetMethod( urlString );
try {
execMethod( client, method );
return method.getResponseBodyAsString();
} finally {
method.releaseConnection();
}
}
public static String execService( VariableSpace space, String hostname, String port, String webAppName,
String serviceAndArguments, String username, String password, String proxyHostname, String proxyPort,
String nonProxyHosts ) throws Exception {
return execService( space, hostname, port, webAppName, serviceAndArguments, username, password, proxyHostname,
proxyPort, nonProxyHosts, false );
}
public static int execMethod( HttpClient client, HttpMethod method ) throws Exception {
int result;
try {
result = client.executeMethod( method );
} catch ( Exception e ) {
throw new KettleException(
"You don't seem to be getting a connection to the server. Check the host and port you're using and make sure the sever is up and running." );
}
if ( result == 500 ) {
throw new KettleException( "There was an error reading data from the server." );
}
if ( result == 401 ) {
throw new KettleException(
"Nice try-but we couldn't log you in. Check your username and password and try again." );
}
if ( result != 200 ) {
throw new KettleException( method.getResponseBodyAsString() );
}
return result;
}
/**
* Returns http GET request string using specified parameters.
*
* @param space
* @param hostname
* @param port
* @param webAppName
* @param serviceAndArguments
* @return
* @throws UnsupportedEncodingException
*/
public static String constructUrl( VariableSpace space, String hostname, String port, String webAppName,
String serviceAndArguments ) throws UnsupportedEncodingException {
return constructUrl( space, hostname, port, webAppName, serviceAndArguments, false );
}
public static String constructUrl( VariableSpace space, String hostname, String port, String webAppName,
String serviceAndArguments, boolean isSecure ) throws UnsupportedEncodingException {
String realHostname = space.environmentSubstitute( hostname );
if ( !StringUtils.isEmpty( webAppName ) ) {
serviceAndArguments = "/" + space.environmentSubstitute( webAppName ) + serviceAndArguments;
}
String protocol = isSecure ? PROTOCOL_SECURE : PROTOCOL_UNSECURE;
String retval = protocol + "://" + realHostname + getPortSpecification( space, port ) + serviceAndArguments;
retval = Const.replace( retval, " ", "%20" );
return retval;
}
public static String getPortSpecification( VariableSpace space, String port ) {
String realPort = space.environmentSubstitute( port );
String portSpec = ":" + realPort;
if ( Utils.isEmpty( realPort ) || port.equals( "80" ) ) {
portSpec = "";
}
return portSpec;
}
public static void addProxy( HttpClient client, VariableSpace space, String hostname, String proxyHostname,
String proxyPort, String nonProxyHosts ) {
String host = space.environmentSubstitute( hostname );
String phost = space.environmentSubstitute( proxyHostname );
String pport = space.environmentSubstitute( proxyPort );
String nonprox = space.environmentSubstitute( nonProxyHosts );
/** added by shingo.yamagami@ksk-sol.jp **/
if ( !Utils.isEmpty( phost ) && !Utils.isEmpty( pport ) ) {
// skip applying proxy if non-proxy host matches
if ( !Utils.isEmpty( nonprox ) && !Utils.isEmpty( host ) && host.matches( nonprox ) ) {
return;
}
client.getHostConfiguration().setProxy( phost, Integer.parseInt( pport ) );
}
/** added by shingo.yamagami@ksk-sol.jp **/
}
public static void addCredentials( HttpClient client, VariableSpace space, String hostname, String port,
String webAppName, String username, String password ) {
if ( StringUtils.isEmpty( webAppName ) ) {
client.getState().setCredentials(
new AuthScope( space.environmentSubstitute( hostname ), Const.toInt(
space.environmentSubstitute( port ), 80 ), "Kettle" ),
new UsernamePasswordCredentials( space.environmentSubstitute( username ), Encr
.decryptPasswordOptionallyEncrypted( space.environmentSubstitute( password ) ) ) );
} else {
Credentials creds =
new UsernamePasswordCredentials( space.environmentSubstitute( username ), Encr
.decryptPasswordOptionallyEncrypted( space.environmentSubstitute( password ) ) );
client.getState().setCredentials( AuthScope.ANY, creds );
client.getParams().setAuthenticationPreemptive( true );
}
}
/**
* Base 64 decode, unzip and extract text using {@link Const#XML_ENCODING} predefined charset value for byte-wise
* multi-byte character handling.
*
* @param loggingString64
* base64 zip archive string representation
* @return text from zip archive
* @throws IOException
*/
public static String decodeBase64ZippedString( String loggingString64 ) throws IOException {
if ( loggingString64 == null || loggingString64.isEmpty() ) {
return "";
}
StringWriter writer = new StringWriter();
// base 64 decode
byte[] bytes64 = Base64.decodeBase64( loggingString64.getBytes() );
// unzip to string encoding-wise
ByteArrayInputStream zip = new ByteArrayInputStream( bytes64 );
GZIPInputStream unzip = null;
InputStreamReader reader = null;
BufferedInputStream in = null;
try {
unzip = new GZIPInputStream( zip, HttpUtil.ZIP_BUFFER_SIZE );
in = new BufferedInputStream( unzip, HttpUtil.ZIP_BUFFER_SIZE );
// PDI-4325 originally used xml encoding in servlet
reader = new InputStreamReader( in, Const.XML_ENCODING );
writer = new StringWriter();
// use same buffer size
char[] buff = new char[HttpUtil.ZIP_BUFFER_SIZE];
for ( int length = 0; ( length = reader.read( buff ) ) > 0; ) {
writer.write( buff, 0, length );
}
} finally {
// close resources
if ( reader != null ) {
try {
reader.close();
} catch ( IOException e ) {
// Suppress
}
}
if ( in != null ) {
try {
in.close();
} catch ( IOException e ) {
// Suppress
}
}
if ( unzip != null ) {
try {
unzip.close();
} catch ( IOException e ) {
// Suppress
}
}
}
return writer.toString();
}
public static String encodeBase64ZippedString( String in ) throws IOException {
Charset charset = Charset.forName( Const.XML_ENCODING );
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = new GZIPOutputStream( baos );
gzos.write( in.getBytes( charset ) );
gzos.close();
return new String( Base64.encodeBase64( baos.toByteArray() ) );
}
}