/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* 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.apache.axis.components.net;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.encoding.Base64;
import org.apache.axis.transport.http.HTTPConstants;
import org.apache.axis.utils.Messages;
import org.apache.commons.logging.Log;
import java.net.Socket;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* Default socket factory.
*
* @author Davanum Srinivas (dims@yahoo.com)
*/
public class DefaultSocketFactory implements SocketFactory {
/** Field log */
protected static Log log =
LogFactory.getLog(DefaultSocketFactory.class.getName());
/** Field CONNECT_TIMEOUT */
public static String CONNECT_TIMEOUT = "axis.client.connect.timeout";
/** attributes */
protected Hashtable attributes = null;
private static boolean plain;
private static Class inetClass;
private static Constructor inetConstructor;
private static Constructor socketConstructor;
private static Method connect;
static {
try {
inetClass = Class.forName("java.net.InetSocketAddress");
plain = false;
inetConstructor = inetClass.getConstructor(new Class[]{String.class, int.class});
socketConstructor = Socket.class.getConstructor(new Class[]{});
connect = Socket.class.getMethod("connect", new Class[]{inetClass.getSuperclass(),
int.class});
} catch (Exception e) {
plain = true;
}
}
/**
* Constructor is used only by subclasses.
*
* @param attributes
*/
public DefaultSocketFactory(Hashtable attributes) {
this.attributes = attributes;
}
/**
* Creates a socket.
*
* @param host
* @param port
* @param otherHeaders
* @param useFullURL
*
* @return Socket
*
* @throws Exception
*/
public Socket create(
String host, int port, StringBuffer otherHeaders, BooleanHolder useFullURL)
throws Exception {
int timeout = 0;
if (attributes != null) {
String value = (String)attributes.get(CONNECT_TIMEOUT);
timeout = (value != null) ? Integer.parseInt(value) : 0;
}
TransportClientProperties tcp = TransportClientPropertiesFactory.create("http");
Socket sock = null;
boolean hostInNonProxyList = isHostInNonProxyList(host, tcp.getNonProxyHosts());
if (tcp.getProxyUser().length() != 0) {
StringBuffer tmpBuf = new StringBuffer();
tmpBuf.append(tcp.getProxyUser())
.append(":")
.append(tcp.getProxyPassword());
otherHeaders.append(HTTPConstants.HEADER_PROXY_AUTHORIZATION)
.append(": Basic ")
.append(Base64.encode(tmpBuf.toString().getBytes()))
.append("\r\n");
}
if (port == -1) {
port = 80;
}
if ((tcp.getProxyHost().length() == 0) ||
(tcp.getProxyPort().length() == 0) ||
hostInNonProxyList)
{
sock = create(host, port, timeout);
if (log.isDebugEnabled()) {
log.debug(Messages.getMessage("createdHTTP00"));
}
} else {
sock = create(tcp.getProxyHost(),
new Integer(tcp.getProxyPort()).intValue(),
timeout);
if (log.isDebugEnabled()) {
log.debug(Messages.getMessage("createdHTTP01", tcp.getProxyHost(),
tcp.getProxyPort()));
}
useFullURL.value = true;
}
return sock;
}
/**
* Creates a socket with connect timeout using reflection API
*
* @param host
* @param port
* @param timeout
* @return
* @throws Exception
*/
private static Socket create(String host, int port, int timeout) throws Exception {
Socket sock = null;
if (plain || timeout == 0) {
sock = new Socket(host, port);
} else {
Object address = inetConstructor.newInstance(new Object[]{host, new Integer(port)});
sock = (Socket)socketConstructor.newInstance(new Object[]{});
connect.invoke(sock, new Object[]{address, new Integer(timeout)});
}
return sock;
}
/**
* Check if the specified host is in the list of non proxy hosts.
*
* @param host host name
* @param nonProxyHosts string containing the list of non proxy hosts
*
* @return true/false
*/
protected boolean isHostInNonProxyList(String host, String nonProxyHosts) {
if ((nonProxyHosts == null) || (host == null)) {
return false;
}
/*
* The http.nonProxyHosts system property is a list enclosed in
* double quotes with items separated by a vertical bar.
*/
StringTokenizer tokenizer = new StringTokenizer(nonProxyHosts, "|\"");
while (tokenizer.hasMoreTokens()) {
String pattern = tokenizer.nextToken();
if (log.isDebugEnabled()) {
log.debug(Messages.getMessage("match00",
new String[]{"HTTPSender",
host,
pattern}));
}
if (match(pattern, host, false)) {
return true;
}
}
return false;
}
/**
* Matches a string against a pattern. The pattern contains two special
* characters:
* '*' which means zero or more characters,
*
* @param pattern the (non-null) pattern to match against
* @param str the (non-null) string that must be matched against the
* pattern
* @param isCaseSensitive
*
* @return <code>true</code> when the string matches against the pattern,
* <code>false</code> otherwise.
*/
protected static boolean match(String pattern, String str,
boolean isCaseSensitive) {
char[] patArr = pattern.toCharArray();
char[] strArr = str.toCharArray();
int patIdxStart = 0;
int patIdxEnd = patArr.length - 1;
int strIdxStart = 0;
int strIdxEnd = strArr.length - 1;
char ch;
boolean containsStar = false;
for (int i = 0; i < patArr.length; i++) {
if (patArr[i] == '*') {
containsStar = true;
break;
}
}
if (!containsStar) {
// No '*'s, so we make a shortcut
if (patIdxEnd != strIdxEnd) {
return false; // Pattern and string do not have the same size
}
for (int i = 0; i <= patIdxEnd; i++) {
ch = patArr[i];
if (isCaseSensitive && (ch != strArr[i])) {
return false; // Character mismatch
}
if (!isCaseSensitive
&& (Character.toUpperCase(ch)
!= Character.toUpperCase(strArr[i]))) {
return false; // Character mismatch
}
}
return true; // String matches against pattern
}
if (patIdxEnd == 0) {
return true; // Pattern contains only '*', which matches anything
}
// Process characters before first star
while ((ch = patArr[patIdxStart]) != '*'
&& (strIdxStart <= strIdxEnd)) {
if (isCaseSensitive && (ch != strArr[strIdxStart])) {
return false; // Character mismatch
}
if (!isCaseSensitive
&& (Character.toUpperCase(ch)
!= Character.toUpperCase(strArr[strIdxStart]))) {
return false; // Character mismatch
}
patIdxStart++;
strIdxStart++;
}
if (strIdxStart > strIdxEnd) {
// All characters in the string are used. Check if only '*'s are
// left in the pattern. If so, we succeeded. Otherwise failure.
for (int i = patIdxStart; i <= patIdxEnd; i++) {
if (patArr[i] != '*') {
return false;
}
}
return true;
}
// Process characters after last star
while ((ch = patArr[patIdxEnd]) != '*' && (strIdxStart <= strIdxEnd)) {
if (isCaseSensitive && (ch != strArr[strIdxEnd])) {
return false; // Character mismatch
}
if (!isCaseSensitive
&& (Character.toUpperCase(ch)
!= Character.toUpperCase(strArr[strIdxEnd]))) {
return false; // Character mismatch
}
patIdxEnd--;
strIdxEnd--;
}
if (strIdxStart > strIdxEnd) {
// All characters in the string are used. Check if only '*'s are
// left in the pattern. If so, we succeeded. Otherwise failure.
for (int i = patIdxStart; i <= patIdxEnd; i++) {
if (patArr[i] != '*') {
return false;
}
}
return true;
}
// process pattern between stars. padIdxStart and patIdxEnd point
// always to a '*'.
while ((patIdxStart != patIdxEnd) && (strIdxStart <= strIdxEnd)) {
int patIdxTmp = -1;
for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
if (patArr[i] == '*') {
patIdxTmp = i;
break;
}
}
if (patIdxTmp == patIdxStart + 1) {
// Two stars next to each other, skip the first one.
patIdxStart++;
continue;
}
// Find the pattern between padIdxStart & padIdxTmp in str between
// strIdxStart & strIdxEnd
int patLength = (patIdxTmp - patIdxStart - 1);
int strLength = (strIdxEnd - strIdxStart + 1);
int foundIdx = -1;
strLoop:
for (int i = 0; i <= strLength - patLength; i++) {
for (int j = 0; j < patLength; j++) {
ch = patArr[patIdxStart + j + 1];
if (isCaseSensitive
&& (ch != strArr[strIdxStart + i + j])) {
continue strLoop;
}
if (!isCaseSensitive && (Character
.toUpperCase(ch) != Character
.toUpperCase(strArr[strIdxStart + i + j]))) {
continue strLoop;
}
}
foundIdx = strIdxStart + i;
break;
}
if (foundIdx == -1) {
return false;
}
patIdxStart = patIdxTmp;
strIdxStart = foundIdx + patLength;
}
// All characters in the string are used. Check if only '*'s are left
// in the pattern. If so, we succeeded. Otherwise failure.
for (int i = patIdxStart; i <= patIdxEnd; i++) {
if (patArr[i] != '*') {
return false;
}
}
return true;
}
}
|