You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by di...@apache.org on 2003/06/28 21:15:16 UTC
cvs commit: xml-axis/java/src/org/apache/axis/transport/http CommonsHTTPSender.java
dims 2003/06/28 12:15:16
Modified: java/src/org/apache/axis/transport/http
CommonsHTTPSender.java
Log:
Fix from "Chandra Talluri" <ct...@netnumber.com> for maintaining sessions and do multiple requests without closing the stream.
See http://marc.theaimsgroup.com/?l=axis-user&m=105681087530198&w=2 for details.
Revision Changes Path
1.16 +145 -132 xml-axis/java/src/org/apache/axis/transport/http/CommonsHTTPSender.java
Index: CommonsHTTPSender.java
===================================================================
RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/transport/http/CommonsHTTPSender.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- CommonsHTTPSender.java 22 Apr 2003 19:35:51 -0000 1.15
+++ CommonsHTTPSender.java 28 Jun 2003 19:15:16 -0000 1.16
@@ -57,29 +57,31 @@
import org.apache.axis.AxisFault;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
-import org.apache.axis.soap.SOAPConstants;
-import org.apache.axis.soap.SOAP12Constants;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.components.net.TransportClientProperties;
import org.apache.axis.components.net.TransportClientPropertiesFactory;
import org.apache.axis.encoding.Base64;
import org.apache.axis.handlers.BasicHandler;
+import org.apache.axis.soap.SOAP12Constants;
+import org.apache.axis.soap.SOAPConstants;
import org.apache.axis.utils.Messages;
+import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
-import org.apache.commons.httpclient.HttpMethodBase;
-import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
-import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.net.URL;
import java.util.Hashtable;
import java.util.StringTokenizer;
@@ -88,13 +90,19 @@
* This class uses Jakarta Commons's HttpClient to call a SOAP server.
*
* @author Davanum Srinivas (dims@yahoo.com)
+ * History: By Chandra Talluri
+ * Modifications done for maintaining sessions. Cookies needed to be set on
+ * HttpState not on MessageContext, since ttpMethodBase overwrites the cookies
+ * from HttpState. Also we need to setCookiePolicy on HttpState to
+ * CookiePolicy.COMPATIBILITY else it is defaulting to RFC2109Spec and adding
+ * Version information to it and tomcat server not recognizing it
*/
public class CommonsHTTPSender extends BasicHandler {
-
+
/** Field log */
protected static Log log =
- LogFactory.getLog(CommonsHTTPSender.class.getName());
-
+ LogFactory.getLog(CommonsHTTPSender.class.getName());
+
private HttpConnectionManager connectionManager;
public CommonsHTTPSender() {
@@ -102,7 +110,7 @@
// declarative configuration
connectionManager = new MultiThreadedHttpConnectionManager();
}
-
+
/**
* invoke creates a socket connection, sends the request SOAP message and then
* reads the response SOAP message back from the SOAP server
@@ -113,26 +121,25 @@
*/
public void invoke(MessageContext msgContext) throws AxisFault {
HttpMethodBase method = null;
-
if (log.isDebugEnabled()) {
log.debug(Messages.getMessage("enter00",
- "CommonsHTTPSender::invoke"));
+ "CommonsHTTPSender::invoke"));
}
try {
URL targetURL =
- new URL(msgContext.getStrProp(MessageContext.TRANS_URL));
-
+ new URL(msgContext.getStrProp(MessageContext.TRANS_URL));
+
// no need to retain these, as the cookies/credentials are
// stored in the message context across multiple requests.
// the underlying connection manager, however, is retained
// so sockets get recycled when possible.
HttpClient httpClient = new HttpClient(connectionManager);
-
+
HostConfiguration hostConfiguration = getHostConfiguration(httpClient, targetURL);
-
+
String webMethod = null;
boolean posting = true;
-
+
// If we're SOAP 1.2, allow the web method to be set from the
// MessageContext.
if (msgContext.getSOAPConstants() == SOAPConstants.SOAP12_CONSTANTS) {
@@ -154,54 +161,74 @@
method = new GetMethod(targetURL.toString());
addContextInfo(method, httpClient, msgContext, targetURL);
}
-
+ // don't forget the cookies!
+ // Cookies need to be set on HttpState, since HttpMethodBase
+ // overwrites the cookies from HttpState
+ if (msgContext.getMaintainSession()) {
+ HttpState state = httpClient.getState();
+ state.setCookiePolicy(CookiePolicy.COMPATIBILITY);
+ String host = hostConfiguration.getHost();
+ String path = targetURL.getPath();
+ boolean secure = hostConfiguration.getProtocol().isSecure();
+ String ck1 = (String)msgContext.getProperty(HTTPConstants.HEADER_COOKIE);
+
+ String ck2 = (String)msgContext.getProperty(HTTPConstants.HEADER_COOKIE2);
+ if (ck1 != null) {
+ int index = ck1.indexOf('=');
+ state.addCookie(new Cookie(host,ck1.substring(0, index),ck1.substring(index+1),path,null,secure));
+ }
+ if (ck2 != null) {
+ int index = ck2.indexOf('=');
+ state.addCookie(new Cookie(host,ck2.substring(0, index),ck2.substring(index+1),path,null,secure));
+ }
+ httpClient.setState(state);
+ }
int returnCode = httpClient.executeMethod(method);
String contentType = null;
String contentLocation = null;
String contentLength = null;
-
if (method.getResponseHeader(HTTPConstants.HEADER_CONTENT_TYPE)
- != null) {
+ != null) {
contentType = method.getResponseHeader(
- HTTPConstants.HEADER_CONTENT_TYPE).getValue();
+ HTTPConstants.HEADER_CONTENT_TYPE).getValue();
}
if (method.getResponseHeader(HTTPConstants.HEADER_CONTENT_LOCATION)
- != null) {
+ != null) {
contentLocation = method.getResponseHeader(
- HTTPConstants.HEADER_CONTENT_LOCATION).getValue();
+ HTTPConstants.HEADER_CONTENT_LOCATION).getValue();
}
if (method.getResponseHeader(HTTPConstants.HEADER_CONTENT_LENGTH)
- != null) {
+ != null) {
contentLength = method.getResponseHeader(
- HTTPConstants.HEADER_CONTENT_LENGTH).getValue();
+ HTTPConstants.HEADER_CONTENT_LENGTH).getValue();
}
contentType = (null == contentType)
- ? null
- : contentType.trim();
+ ? null
+ : contentType.trim();
if ((returnCode > 199) && (returnCode < 300)) {
-
+
// SOAP return is OK - so fall through
} else if (msgContext.getSOAPConstants() ==
- SOAPConstants.SOAP12_CONSTANTS) {
+ SOAPConstants.SOAP12_CONSTANTS) {
// For now, if we're SOAP 1.2, fall through, since the range of
// valid result codes is much greater
} else if ((contentType != null) && !contentType.equals("text/html")
- && ((returnCode > 499) && (returnCode < 600))) {
-
+ && ((returnCode > 499) && (returnCode < 600))) {
+
// SOAP Fault should be in here - so fall through
} else {
String statusMessage = method.getStatusText();
AxisFault fault = new AxisFault("HTTP",
- "(" + returnCode + ")"
- + statusMessage, null,
- null);
-
+ "(" + returnCode + ")"
+ + statusMessage, null,
+ null);
+
fault.setFaultDetailString(Messages.getMessage("return01",
- "" + returnCode, method.getResponseBodyAsString()));
+ "" + returnCode, method.getResponseBodyAsString()));
throw fault;
}
Message outMsg = new Message(method.getResponseBodyAsStream(),
- false, contentType, contentLocation);
+ false, contentType, contentLocation);
// no need to invoke method.releaseConnection here, as that will
// happen automatically when the response body is read.
// issue: what if the stream is never closed? Are we certain
@@ -211,13 +238,13 @@
if (log.isDebugEnabled()) {
if (null == contentLength) {
log.debug("\n"
- + Messages.getMessage("no00", "Content-Length"));
+ + Messages.getMessage("no00", "Content-Length"));
}
log.debug("\n" + Messages.getMessage("xmlRecd00"));
log.debug("-----------------------------------------------");
- log.debug((String) outMsg.getSOAPPartAsString());
+ log.debug(outMsg.getSOAPPartAsString());
}
-
+
// if we are maintaining session state,
// handle cookies (if any)
if (msgContext.getMaintainSession()) {
@@ -228,7 +255,9 @@
else if (headers[i].getName().equalsIgnoreCase(HTTPConstants.HEADER_SET_COOKIE2))
msgContext.setProperty(HTTPConstants.HEADER_COOKIE2, cleanupCookie(headers[i].getValue()));
}
+
}
+
} catch (Exception e) {
log.debug(e);
throw AxisFault.makeFault(e);
@@ -236,10 +265,10 @@
if (log.isDebugEnabled()) {
log.debug(Messages.getMessage("exit00",
- "CommonsHTTPSender::invoke"));
+ "CommonsHTTPSender::invoke"));
}
}
-
+
/**
* cleanup the cookie value.
*
@@ -251,34 +280,33 @@
cookie = cookie.trim();
// chop after first ; a la Apache SOAP (see HTTPUtils.java there)
int index = cookie.indexOf(';');
-
+
if (index != -1) {
cookie = cookie.substring(0, index);
}
return cookie;
}
-
+
private HostConfiguration getHostConfiguration(HttpClient client, URL targetURL) {
- boolean isSecure = targetURL.getProtocol().equalsIgnoreCase("http");
TransportClientProperties tcp = TransportClientPropertiesFactory.create(targetURL.getProtocol()); // http or https
int port = targetURL.getPort();
boolean hostInNonProxyList =
- isHostInNonProxyList(targetURL.getHost(), tcp.getNonProxyHosts());
-
+ isHostInNonProxyList(targetURL.getHost(), tcp.getNonProxyHosts());
+
HostConfiguration config = new HostConfiguration();
if (port == -1) {
port = 80; // even for https
}
if (tcp.getProxyHost().length() == 0 ||
- tcp.getProxyPort().length() == 0 ||
- hostInNonProxyList) {
+ tcp.getProxyPort().length() == 0 ||
+ hostInNonProxyList) {
config.setHost(targetURL.getHost(), port, targetURL.getProtocol());
} else {
if (tcp.getProxyUser().length() != 0) {
Credentials proxyCred =
- new UsernamePasswordCredentials(tcp.getProxyUser(),
- tcp.getProxyPassword());
+ new UsernamePasswordCredentials(tcp.getProxyUser(),
+ tcp.getProxyPassword());
client.getState().setProxyCredentials(null, proxyCred);
}
int proxyPort = new Integer(tcp.getProxyPort()).intValue();
@@ -286,7 +314,7 @@
}
return config;
}
-
+
/**
* Extracts info from message context.
*
@@ -298,37 +326,37 @@
* @throws Exception
*/
private void addContextInfo(
- HttpMethodBase method, HttpClient httpClient, MessageContext msgContext, URL tmpURL)
- throws Exception {
-
+ HttpMethodBase method, HttpClient httpClient, MessageContext msgContext, URL tmpURL)
+ throws Exception {
+
// optionally set a timeout for the request
if (msgContext.getTimeout() != 0) {
httpClient.setTimeout(msgContext.getTimeout());
}
-
+
// Get SOAPAction, default to ""
String action = msgContext.useSOAPAction()
- ? msgContext.getSOAPActionURI()
- : "";
-
+ ? msgContext.getSOAPActionURI()
+ : "";
+
if (action == null) {
action = "";
}
Message msg = msgContext.getRequestMessage();
if (msg != null){
method.setRequestHeader(new Header(HTTPConstants.HEADER_CONTENT_TYPE,
- msg.getContentType(msgContext.getSOAPConstants())));
+ msg.getContentType(msgContext.getSOAPConstants())));
}
method.setRequestHeader(new Header(HTTPConstants.HEADER_SOAP_ACTION, "\"" + action + "\""));
String userID = msgContext.getUsername();
String passwd = msgContext.getPassword();
-
+
// if UserID is not part of the context, but is in the URL, use
// the one in the URL.
if ((userID == null) && (tmpURL.getUserInfo() != null)) {
String info = tmpURL.getUserInfo();
int sep = info.indexOf(':');
-
+
if ((sep >= 0) && (sep + 1 < info.length())) {
userID = info.substring(0, sep);
passwd = info.substring(sep + 1);
@@ -339,50 +367,35 @@
if (userID != null) {
Credentials cred = new UsernamePasswordCredentials(userID, passwd);
httpClient.getState().setCredentials(null, cred);
-
+
// The following 3 lines should NOT be required. But Our SimpleAxisServer fails
// during all-tests if this is missing.
StringBuffer tmpBuf = new StringBuffer();
tmpBuf.append(userID).append(":").append((passwd == null) ? "" : passwd);
method.addRequestHeader(HTTPConstants.HEADER_AUTHORIZATION, "Basic " + Base64.encode(tmpBuf.toString().getBytes()));
}
-
- // don't forget the cookies!
- if (msgContext.getMaintainSession()) {
- String cookie =
- (String) msgContext.getProperty(HTTPConstants.HEADER_COOKIE);
- String cookie2 =
- (String) msgContext.getProperty(HTTPConstants.HEADER_COOKIE2);
-
- if (cookie != null) {
- method.addRequestHeader(HTTPConstants.HEADER_COOKIE, cookie);
- }
- if (cookie2 != null) {
- method.addRequestHeader(HTTPConstants.HEADER_COOKIE2, cookie2);
- }
- }
-
+
// process user defined headers for information.
Hashtable userHeaderTable =
- (Hashtable) msgContext.getProperty(HTTPConstants.REQUEST_HEADERS);
-
+ (Hashtable) msgContext.getProperty(HTTPConstants.REQUEST_HEADERS);
+
if (userHeaderTable != null) {
for (java.util.Iterator e = userHeaderTable.entrySet().iterator();
- e.hasNext();) {
+ e.hasNext();) {
java.util.Map.Entry me = (java.util.Map.Entry) e.next();
Object keyObj = me.getKey();
-
+
if (null == keyObj) {
continue;
}
String key = keyObj.toString().trim();
String value = me.getValue().toString().trim();
-
+
method.addRequestHeader(key, value);
}
}
}
-
+
/**
* Check if the specified host is in the list of non proxy hosts.
*
@@ -392,25 +405,25 @@
* @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}));
+ new String[]{"HTTPSender",
+ host,
+ pattern}));
}
if (match(pattern, host, false)) {
return true;
@@ -418,7 +431,7 @@
}
return false;
}
-
+
/**
* Matches a string against a pattern. The pattern contains two special
* characters:
@@ -433,8 +446,8 @@
* <code>false</code> otherwise.
*/
protected static boolean match(String pattern, String str,
- boolean isCaseSensitive) {
-
+ boolean isCaseSensitive) {
+
char[] patArr = pattern.toCharArray();
char[] strArr = str.toCharArray();
int patIdxStart = 0;
@@ -443,7 +456,7 @@
int strIdxEnd = strArr.length - 1;
char ch;
boolean containsStar = false;
-
+
for (int i = 0; i < patArr.length; i++) {
if (patArr[i] == '*') {
containsStar = true;
@@ -451,7 +464,7 @@
}
}
if (!containsStar) {
-
+
// No '*'s, so we make a shortcut
if (patIdxEnd != strIdxEnd) {
return false; // Pattern and string do not have the same size
@@ -462,8 +475,8 @@
return false; // Character mismatch
}
if (!isCaseSensitive
- && (Character.toUpperCase(ch)
- != Character.toUpperCase(strArr[i]))) {
+ && (Character.toUpperCase(ch)
+ != Character.toUpperCase(strArr[i]))) {
return false; // Character mismatch
}
}
@@ -472,23 +485,23 @@
if (patIdxEnd == 0) {
return true; // Pattern contains only '*', which matches anything
}
-
+
// Process characters before first star
while ((ch = patArr[patIdxStart]) != '*'
- && (strIdxStart <= strIdxEnd)) {
+ && (strIdxStart <= strIdxEnd)) {
if (isCaseSensitive && (ch != strArr[strIdxStart])) {
return false; // Character mismatch
}
if (!isCaseSensitive
- && (Character.toUpperCase(ch)
- != Character.toUpperCase(strArr[strIdxStart]))) {
+ && (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++) {
@@ -498,22 +511,22 @@
}
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]))) {
+ && (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++) {
@@ -523,12 +536,12 @@
}
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;
@@ -536,42 +549,42 @@
}
}
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
+ 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;
+ continue strLoop;
+ }
+ if (!isCaseSensitive && (Character
+ .toUpperCase(ch) != Character
+ .toUpperCase(strArr[strIdxStart + i + j]))) {
+ continue strLoop;
+ }
}
+ foundIdx = strIdxStart + i;
+ break;
}
- foundIdx = strIdxStart + i;
- break;
- }
- if (foundIdx == -1) {
- return false;
- }
- patIdxStart = patIdxTmp;
- strIdxStart = foundIdx + patLength;
+ 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++) {