This is an automated email from the ASF dual-hosted git repository. billblough pushed a commit to branch AXIS2-4318 in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git
commit 26ea9b937f142fe9a022e99939d97d8e34536a68 Author: Sagara Gunathunga <sag...@apache.org> AuthorDate: Mon Apr 30 10:04:10 2012 +0000 Apply latest patch for AXIS2-4318. --- .../impl/httpclient4/HTTPProxyConfigurator.java | 462 ++++++++++ .../http/impl/httpclient4/HTTPSenderImpl.java | 997 +++++++++++++++++++++ .../transport/http/HTTPClient4SenderTest.java | 178 ++++ .../axis2/transport/http/HTTPSenderTest.java | 13 +- 4 files changed, 1643 insertions(+), 7 deletions(-) diff --git a/modules/transport/http/src/org/apache/axis2/transport/http/impl/httpclient4/HTTPProxyConfigurator.java b/modules/transport/http/src/org/apache/axis2/transport/http/impl/httpclient4/HTTPProxyConfigurator.java new file mode 100644 index 0000000..67615f4 --- /dev/null +++ b/modules/transport/http/src/org/apache/axis2/transport/http/impl/httpclient4/HTTPProxyConfigurator.java @@ -0,0 +1,462 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.axis2.transport.http.impl.httpclient4; + +import org.apache.axiom.om.OMElement; +import org.apache.axis2.AxisFault; +import org.apache.axis2.context.MessageContext; +import org.apache.axis2.description.Parameter; +import org.apache.axis2.transport.http.HTTPConstants; +import org.apache.axis2.transport.http.HTTPTransportConstants; +import org.apache.axis2.transport.http.HttpTransportProperties; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.NTCredentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.params.ClientPNames; +import org.apache.http.conn.params.ConnRoutePNames; +import org.apache.http.impl.client.AbstractHttpClient; + +import javax.xml.namespace.QName; +import java.net.URL; +import java.util.StringTokenizer; + + +public class HTTPProxyConfigurator { + + private static Log log = LogFactory.getLog(HTTPProxyConfigurator.class); + + /** + * Configure HTTP Proxy settings of commons-httpclient HostConfiguration. + * Proxy settings can be get from axis2.xml, Java proxy settings or can be + * override through property in message context. + * <p/> + * HTTP Proxy setting element format: <parameter name="Proxy"> + * <Configuration> <ProxyHost>example.org</ProxyHost> + * <ProxyPort>3128</ProxyPort> <ProxyUser>EXAMPLE/John</ProxyUser> + * <ProxyPassword>password</ProxyPassword> <Configuration> <parameter> + * + * @param messageContext + * in message context for + * @param httpClient + * instance + * @throws org.apache.axis2.AxisFault + * if Proxy settings are invalid + */ + public static void configure(MessageContext messageContext, AbstractHttpClient httpClient) + throws AxisFault { + + Credentials proxyCredentials = null; + String proxyHost = null; + String nonProxyHosts = null; + Integer proxyPort = -1; + String proxyUser = null; + String proxyPassword = null; + + // Getting configuration values from Axis2.xml + Parameter proxySettingsFromAxisConfig = messageContext.getConfigurationContext() + .getAxisConfiguration().getParameter(HTTPTransportConstants.ATTR_PROXY); + if (proxySettingsFromAxisConfig != null) { + OMElement proxyConfiguration = + getProxyConfigurationElement(proxySettingsFromAxisConfig); + proxyHost = getProxyHost(proxyConfiguration); + proxyPort = getProxyPort(proxyConfiguration); + proxyUser = getProxyUser(proxyConfiguration); + proxyPassword = getProxyPassword(proxyConfiguration); + if (proxyUser != null) { + if (proxyPassword == null) { + proxyPassword = ""; + } + int proxyUserDomainIndex = proxyUser.indexOf("\\"); + if (proxyUserDomainIndex > 0) { + String domain = proxyUser.substring(0, proxyUserDomainIndex); + if (proxyUser.length() > proxyUserDomainIndex + 1) { + String user = proxyUser.substring(proxyUserDomainIndex + 1); + proxyCredentials = new NTCredentials(user, proxyPassword, proxyHost, + domain); + } + } + proxyCredentials = new UsernamePasswordCredentials(proxyUser, proxyPassword); + } + + } + + // If there is runtime proxy settings, these settings will override + // settings from axis2.xml + HttpTransportProperties.ProxyProperties proxyProperties = + (HttpTransportProperties.ProxyProperties) messageContext + .getProperty(HTTPConstants.PROXY); + if (proxyProperties != null) { + String proxyHostProp = proxyProperties.getProxyHostName(); + if (proxyHostProp == null || proxyHostProp.length() <= 0) { + throw new AxisFault("HTTP Proxy host is not available. Host is a MUST parameter"); + } else { + proxyHost = proxyHostProp; + } + proxyPort = proxyProperties.getProxyPort(); + + // Overriding credentials + String userName = proxyProperties.getUserName(); + String password = proxyProperties.getPassWord(); + String domain = proxyProperties.getDomain(); + + if (userName != null && password != null && domain != null) { + proxyCredentials = new NTCredentials(userName, password, proxyHost, domain); + } else if (userName != null && domain == null) { + proxyCredentials = new UsernamePasswordCredentials(userName, password); + } + + } + + // Overriding proxy settings if proxy is available from JVM settings + String host = System.getProperty(HTTPTransportConstants.HTTP_PROXY_HOST); + if (host != null) { + proxyHost = host; + } + + String port = System.getProperty(HTTPTransportConstants.HTTP_PROXY_PORT); + if (port != null) { + proxyPort = Integer.parseInt(port); + } + + if (proxyCredentials != null) { + // TODO : Set preemptive authentication, but its not recommended in HC 4 + httpClient.getParams().setParameter(ClientPNames.HANDLE_AUTHENTICATION, true); + + httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, proxyCredentials); + HttpHost proxy = new HttpHost(proxyHost, proxyPort); + httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); + + } + } + + private static OMElement getProxyConfigurationElement(Parameter proxySettingsFromAxisConfig) + throws AxisFault { + OMElement proxyConfigurationElement = proxySettingsFromAxisConfig.getParameterElement() + .getFirstElement(); + if (proxyConfigurationElement == null) { + log.error(HTTPTransportConstants.PROXY_CONFIGURATION_NOT_FOUND); + throw new AxisFault(HTTPTransportConstants.PROXY_CONFIGURATION_NOT_FOUND); + } + return proxyConfigurationElement; + } + + private static String getProxyHost(OMElement proxyConfiguration) throws AxisFault { + OMElement proxyHostElement = proxyConfiguration.getFirstChildWithName(new QName( + HTTPTransportConstants.PROXY_HOST_ELEMENT)); + if (proxyHostElement == null) { + log.error(HTTPTransportConstants.PROXY_HOST_ELEMENT_NOT_FOUND); + throw new AxisFault(HTTPTransportConstants.PROXY_HOST_ELEMENT_NOT_FOUND); + } + String proxyHost = proxyHostElement.getText(); + if (proxyHost == null) { + log.error(HTTPTransportConstants.PROXY_HOST_ELEMENT_WITH_EMPTY_VALUE); + throw new AxisFault(HTTPTransportConstants.PROXY_HOST_ELEMENT_WITH_EMPTY_VALUE); + } + return proxyHost; + } + + private static Integer getProxyPort(OMElement proxyConfiguration) throws AxisFault { + OMElement proxyPortElement = proxyConfiguration.getFirstChildWithName(new QName( + HTTPTransportConstants.PROXY_PORT_ELEMENT)); + if (proxyPortElement == null) { + log.error(HTTPTransportConstants.PROXY_PORT_ELEMENT_NOT_FOUND); + throw new AxisFault(HTTPTransportConstants.PROXY_PORT_ELEMENT_NOT_FOUND); + } + String proxyPort = proxyPortElement.getText(); + if (proxyPort == null) { + log.error(HTTPTransportConstants.PROXY_PORT_ELEMENT_WITH_EMPTY_VALUE); + throw new AxisFault(HTTPTransportConstants.PROXY_PORT_ELEMENT_WITH_EMPTY_VALUE); + } + return Integer.parseInt(proxyPort); + } + + private static String getProxyUser(OMElement proxyConfiguration) { + OMElement proxyUserElement = proxyConfiguration.getFirstChildWithName(new QName( + HTTPTransportConstants.PROXY_USER_ELEMENT)); + if (proxyUserElement == null) { + return null; + } + String proxyUser = proxyUserElement.getText(); + if (proxyUser == null) { + log.warn("Empty user name element in HTTP Proxy settings."); + return null; + } + + return proxyUser; + } + + private static String getProxyPassword(OMElement proxyConfiguration) { + OMElement proxyPasswordElement = proxyConfiguration.getFirstChildWithName(new QName( + HTTPTransportConstants.PROXY_PASSWORD_ELEMENT)); + if (proxyPasswordElement == null) { + return null; + } + String proxyUser = proxyPasswordElement.getText(); + if (proxyUser == null) { + log.warn("Empty user name element in HTTP Proxy settings."); + return null; + } + + return proxyUser; + } + + /** + * Check whether http proxy is configured or active. This is not a deep + * check. + * + * @param messageContext + * in message context + * @param targetURL + * URL of the edpoint which we are sending the request + * @return true if proxy is enabled, false otherwise + */ + public static boolean isProxyEnabled(MessageContext messageContext, URL targetURL) { + boolean proxyEnabled = false; + + Parameter param = messageContext.getConfigurationContext().getAxisConfiguration() + .getParameter(HTTPTransportConstants.ATTR_PROXY); + + // If configuration is over ridden + Object obj = messageContext.getProperty(HTTPConstants.PROXY); + + // From Java Networking Properties + String sp = System.getProperty(HTTPTransportConstants.HTTP_PROXY_HOST); + + if (param != null || obj != null || sp != null) { + proxyEnabled = true; + } + + boolean isNonProxyHost = validateNonProxyHosts(targetURL.getHost()); + + return proxyEnabled && !isNonProxyHost; + } + + /** + * Validates for names that shouldn't be listered as proxies. The + * http.nonProxyHosts can be set to specify the hosts which should be + * connected to directly (not through the proxy server). The value of the + * http.nonProxyHosts property can be a list of hosts, each separated by a + * |; it can also take a regular expression for matches; for example: + * *.sfbay.sun.com would match any fully qualified hostname in the sfbay + * domain. + * <p/> + * For more information refer to : + * http://java.sun.com/features/2002/11/hilevel_network.html + * <p/> + * false : validation fail : User can use the proxy true : validation pass ; + * User can't use the proxy + * + * @return boolean + */ + private static boolean validateNonProxyHosts(String host) { + // From system property http.nonProxyHosts + String nonProxyHosts = System.getProperty(HTTPTransportConstants.HTTP_NON_PROXY_HOSTS); + return isHostInNonProxyList(host, nonProxyHosts); + } + + /** + * 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 + */ + public static 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 (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. + */ + private 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; + } + +} diff --git a/modules/transport/http/src/org/apache/axis2/transport/http/impl/httpclient4/HTTPSenderImpl.java b/modules/transport/http/src/org/apache/axis2/transport/http/impl/httpclient4/HTTPSenderImpl.java new file mode 100644 index 0000000..7723730 --- /dev/null +++ b/modules/transport/http/src/org/apache/axis2/transport/http/impl/httpclient4/HTTPSenderImpl.java @@ -0,0 +1,997 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.axis2.transport.http.impl.httpclient4; + + +import org.apache.axiom.om.OMAttribute; +import org.apache.axiom.om.OMElement; +import org.apache.axis2.AxisFault; +import org.apache.axis2.Constants; +import org.apache.axis2.context.ConfigurationContext; +import org.apache.axis2.context.MessageContext; +import org.apache.axis2.context.NamedValue; +import org.apache.axis2.context.OperationContext; +import org.apache.axis2.i18n.Messages; +import org.apache.axis2.transport.MessageFormatter; +import org.apache.axis2.transport.TransportUtils; +import org.apache.axis2.transport.http.HTTPAuthenticator; +import org.apache.axis2.transport.http.HTTPConstants; +import org.apache.axis2.transport.http.HTTPSender; +import org.apache.axis2.transport.http.HTTPTransportConstants; +import org.apache.axis2.wsdl.WSDLConstants; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.Header; +import org.apache.http.HeaderElement; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.HttpVersion; +import org.apache.http.NameValuePair; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.NTCredentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.params.AuthPolicy; +import org.apache.http.client.params.ClientPNames; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.impl.client.AbstractHttpClient; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.message.BasicHeader; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HTTP; +import org.apache.http.protocol.HttpContext; + +import javax.xml.namespace.QName; +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.zip.GZIPInputStream; + + +public class HTTPSenderImpl extends HTTPSender { + + private static final Log log = LogFactory.getLog(HTTPSenderImpl.class); + + /** + * Used to send a request via HTTP Get method + * + * @param msgContext - The MessageContext of the message + * @param url - The target URL + * @param soapActionString - The soapAction string of the request + * @throws org.apache.axis2.AxisFault - Thrown in case an exception occurs + */ + protected void sendViaGet(MessageContext msgContext, URL url, String soapActionString) + throws AxisFault { + HttpGet httpGet = new HttpGet(); + AbstractHttpClient httpClient = getHttpClient(msgContext); + MessageFormatter messageFormatter = populateCommonProperties(msgContext, url, httpGet, + httpClient, soapActionString); + + // Need to have this here because we can have soap action when using the + // soap response MEP + String soapAction = messageFormatter + .formatSOAPAction(msgContext, format, soapActionString); + + if (soapAction != null) { + httpGet.setHeader(HTTPConstants.HEADER_SOAP_ACTION, soapAction); + } + + /* + * main execution takes place.. + */ + HttpResponse response = null; + try { + response = executeMethod(httpClient, msgContext, url, httpGet); + handleResponse(msgContext, response); + } catch (IOException e) { + log.info("Unable to sendViaGet to url[" + url + "]", e); + throw AxisFault.makeFault(e); + } finally { + cleanup(msgContext, response); + } + } + + @Override + protected void cleanup(MessageContext msgContext, Object httpResponse) { + HttpResponse response; + if (httpResponse instanceof HttpResponse) { + response = (HttpResponse) httpResponse; + } else { + log.trace("HttpResponse expected, but found - " + httpResponse); + return; + } + log.trace("Cleaning response : " + response); + HttpEntity entity = response.getEntity(); + if (entity != null && entity.isStreaming()) { + InputStream inputStream; + try { + inputStream = entity.getContent(); + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + log.error("Error while cleaning response : "+response, e); + } + } + } + + /** + * Used to send a request via HTTP Delete Method + * + * @param msgContext - The MessageContext of the message + * @param url - The target URL + * @param soapActionString - The soapAction string of the request + * @throws org.apache.axis2.AxisFault - Thrown in case an exception occurs + */ + protected void sendViaDelete(MessageContext msgContext, URL url, String soapActionString) + throws AxisFault { + + HttpDelete deleteMethod = new HttpDelete(); + AbstractHttpClient httpClient = getHttpClient(msgContext); + populateCommonProperties(msgContext, url, deleteMethod, httpClient, soapActionString); + + /* + * main execution takes place.. + */ + HttpResponse response = null; + try { + response = executeMethod(httpClient, msgContext, url, deleteMethod); + handleResponse(msgContext, response); + } catch (IOException e) { + log.info("Unable to sendViaDelete to url[" + url + "]", e); + throw AxisFault.makeFault(e); + } finally { + cleanup(msgContext, response); + } + } + + /** + * Used to send a request via HTTP Post Method + * + * @param msgContext - The MessageContext of the message + * @param url - The target URL + * @param soapActionString - The soapAction string of the request + * @throws org.apache.axis2.AxisFault - Thrown in case an exception occurs + */ + protected void sendViaPost(MessageContext msgContext, URL url, String soapActionString) + throws AxisFault { + + AbstractHttpClient httpClient = getHttpClient(msgContext); + + /* + * What's up with this, it never gets used anywhere?? --Glen String + * charEncoding = (String) + * msgContext.getProperty(Constants.Configuration + * .CHARACTER_SET_ENCODING); + * + * if (charEncoding == null) { charEncoding = + * MessageContext.DEFAULT_CHAR_SET_ENCODING; } + */ + + HttpPost postMethod = new HttpPost(); + if (log.isTraceEnabled()) { + log.trace(Thread.currentThread() + " PostMethod " + postMethod + " / " + httpClient); + } + MessageFormatter messageFormatter = populateCommonProperties(msgContext, url, postMethod, + httpClient, soapActionString); + AxisRequestEntityImpl requestEntity = + new AxisRequestEntityImpl(messageFormatter, msgContext, format, + soapActionString, chunked, isAllowedRetry); + postMethod.setEntity(requestEntity); + + if (!httpVersion.equals(HTTPConstants.HEADER_PROTOCOL_10) && chunked) { + requestEntity.setChunked(chunked); + } + + String soapAction = messageFormatter.formatSOAPAction(msgContext, format, soapActionString); + + if (soapAction != null) { + postMethod.setHeader(HTTPConstants.HEADER_SOAP_ACTION, soapAction); + } + + /* + * main execution takes place.. + */ + HttpResponse response = null; + try { + response = executeMethod(httpClient, msgContext, url, postMethod); + handleResponse(msgContext, response); + } catch (IOException e) { + log.info("Unable to sendViaPost to url[" + url + "]", e); + throw AxisFault.makeFault(e); + } finally { + cleanup(msgContext, response); + } + } + + /** + * Used to send a request via HTTP Put Method + * + * @param msgContext - The MessageContext of the message + * @param url - The target URL + * @param soapActionString - The soapAction string of the request + * @throws org.apache.axis2.AxisFault - Thrown in case an exception occurs + */ + protected void sendViaPut(MessageContext msgContext, URL url, String soapActionString) + throws AxisFault { + + AbstractHttpClient httpClient = getHttpClient(msgContext); + + /* + * Same deal - this value never gets used, why is it here? --Glen String + * charEncoding = (String) + * msgContext.getProperty(Constants.Configuration + * .CHARACTER_SET_ENCODING); + * + * if (charEncoding == null) { charEncoding = + * MessageContext.DEFAULT_CHAR_SET_ENCODING; } + */ + + HttpPut putMethod = new HttpPut(); + MessageFormatter messageFormatter = populateCommonProperties(msgContext, url, putMethod, + httpClient, soapActionString); + AxisRequestEntityImpl requestEntity = + new AxisRequestEntityImpl(messageFormatter, msgContext, format, + soapActionString, chunked, isAllowedRetry); + putMethod.setEntity(requestEntity); + + if (!httpVersion.equals(HTTPConstants.HEADER_PROTOCOL_10) && chunked) { + requestEntity.setChunked(chunked); + } + + String soapAction = messageFormatter.formatSOAPAction(msgContext, format, soapActionString); + if (soapAction != null) { + putMethod.setHeader(HTTPConstants.HEADER_SOAP_ACTION, soapAction); + } + + /* + * main execution takes place.. + */ + HttpResponse response = null; + try { + response = executeMethod(httpClient, msgContext, url, putMethod); + handleResponse(msgContext, response); + } catch (IOException e) { + log.info("Unable to sendViaPut to url[" + url + "]", e); + throw AxisFault.makeFault(e); + } finally { + cleanup(msgContext, response); + } + } + + /** + * Used to handle the HTTP Response + * + * @param msgContext - The MessageContext of the message + * @param - The HTTP method used + * @throws java.io.IOException - Thrown in case an exception occurs + */ + protected void handleResponse(MessageContext msgContext, Object httpResponse) + throws IOException { + HttpResponse response; + if (httpResponse instanceof HttpResponse) { + response = (HttpResponse) httpResponse; + } else { + log.trace("HttpResponse expected, but found - " + httpResponse); + return; + } + int statusCode = response.getStatusLine().getStatusCode(); + HTTPStatusCodeFamily family = getHTTPStatusCodeFamily(statusCode); + log.trace("Handling response - " + statusCode); + if (HTTPStatusCodeFamily.SUCCESSFUL.equals(family)) { + // Save the HttpMethod so that we can release the connection when + // cleaning up + // TODO : Do we need to save the http method +// msgContext.setProperty(HTTPConstants.HTTP_METHOD, method); + + processResponse(response, msgContext); + } else if (statusCode == HttpStatus.SC_ACCEPTED) { + /* + * When an HTTP 202 Accepted code has been received, this will be + * the case of an execution of an in-only operation. In such a + * scenario, the HTTP response headers should be returned, i.e. + * session cookies. + */ + obtainHTTPHeaderInformation(response.getEntity(), msgContext); + + } else if (statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR + || statusCode == HttpStatus.SC_BAD_REQUEST) { + // Save the HttpMethod so that we can release the connection when + // cleaning up +// msgContext.setProperty(HTTPConstants.HTTP_METHOD, method); + Header contentTypeHeader = response.getFirstHeader(HTTPConstants.HEADER_CONTENT_TYPE); + String value = null; + if (contentTypeHeader != null) { + value = contentTypeHeader.getValue(); + } + OperationContext opContext = msgContext.getOperationContext(); + if (opContext != null) { + MessageContext inMessageContext = opContext + .getMessageContext(WSDLConstants.MESSAGE_LABEL_IN_VALUE); + if (inMessageContext != null) { + inMessageContext.setProcessingFault(true); + } + } + if (value != null) { + processResponse(response, msgContext); + } + + if (org.apache.axis2.util.Utils.isClientThreadNonBlockingPropertySet(msgContext)) { + throw new AxisFault(Messages. + getMessage("transportError", + String.valueOf(statusCode), + response.getStatusLine().toString())); + } + } else { + throw new AxisFault(Messages.getMessage("transportError", String.valueOf(statusCode), + response.getStatusLine().toString())); + } + } + + /** + * Collect the HTTP header information and set them in the message context + * + * @param httpResponse which holds the header information + * @param msgContext the MessageContext in which to place the information... OR + * NOT! + * @throws AxisFault if problems occur + */ + protected void obtainHTTPHeaderInformation(Object httpResponse, MessageContext msgContext) + throws AxisFault { + HttpResponse response; + if (httpResponse instanceof HttpResponse) { + response = (HttpResponse) httpResponse; + } else { + return; + } + // Set RESPONSE properties onto the REQUEST message context. They will + // need to be copied off the request context onto + // the response context elsewhere, for example in the + // OutInOperationClient. + Map transportHeaders = new HTTPTransportHeaders(response.getAllHeaders()); + msgContext.setProperty(MessageContext.TRANSPORT_HEADERS, transportHeaders); + msgContext.setProperty(HTTPConstants.MC_HTTP_STATUS_CODE, + new Integer(response.getStatusLine().getStatusCode())); + Header header = response.getFirstHeader(HTTPConstants.HEADER_CONTENT_TYPE); + + if (header != null) { + HeaderElement[] headers = header.getElements(); + MessageContext inMessageContext = msgContext.getOperationContext().getMessageContext( + WSDLConstants.MESSAGE_LABEL_IN_VALUE); + + Object contentType = header.getValue(); + Object charSetEnc = null; + + for (int i = 0; i < headers.length; i++) { + NameValuePair charsetEnc = headers[i] + .getParameterByName(HTTPConstants.CHAR_SET_ENCODING); + if (charsetEnc != null) { + charSetEnc = charsetEnc.getValue(); + } + } + + if (inMessageContext != null) { + inMessageContext.setProperty(Constants.Configuration.CONTENT_TYPE, contentType); + inMessageContext.setProperty(Constants.Configuration.CHARACTER_SET_ENCODING, + charSetEnc); + } else { + + // Transport details will be stored in a HashMap so that anybody + // interested can + // retrieve them + HashMap transportInfoMap = new HashMap(); + transportInfoMap.put(Constants.Configuration.CONTENT_TYPE, contentType); + transportInfoMap.put(Constants.Configuration.CHARACTER_SET_ENCODING, charSetEnc); + + // the HashMap is stored in the outgoing message. + msgContext + .setProperty(Constants.Configuration.TRANSPORT_INFO_MAP, transportInfoMap); + } + } + + String sessionCookie = null; + // Process old style headers first + Header[] cookieHeaders = response.getHeaders(HTTPConstants.HEADER_SET_COOKIE); + String customCoookiId = (String) msgContext.getProperty(Constants.CUSTOM_COOKIE_ID); + for (int i = 0; i < cookieHeaders.length; i++) { + HeaderElement[] elements = cookieHeaders[i].getElements(); + for (int e = 0; e < elements.length; e++) { + HeaderElement element = elements[e]; + if (Constants.SESSION_COOKIE.equalsIgnoreCase(element.getName()) + || Constants.SESSION_COOKIE_JSESSIONID.equalsIgnoreCase(element.getName())) { + sessionCookie = processCookieHeader(element); + } + if (customCoookiId != null && customCoookiId.equalsIgnoreCase(element.getName())) { + sessionCookie = processCookieHeader(element); + } + } + } + // Overwrite old style cookies with new style ones if present + cookieHeaders = response.getHeaders(HTTPConstants.HEADER_SET_COOKIE2); + for (int i = 0; i < cookieHeaders.length; i++) { + HeaderElement[] elements = cookieHeaders[i].getElements(); + for (int e = 0; e < elements.length; e++) { + HeaderElement element = elements[e]; + if (Constants.SESSION_COOKIE.equalsIgnoreCase(element.getName()) + || Constants.SESSION_COOKIE_JSESSIONID.equalsIgnoreCase(element.getName())) { + sessionCookie = processCookieHeader(element); + } + if (customCoookiId != null && customCoookiId.equalsIgnoreCase(element.getName())) { + sessionCookie = processCookieHeader(element); + } + } + } + + if (sessionCookie != null) { + msgContext.getServiceContext().setProperty(HTTPConstants.COOKIE_STRING, sessionCookie); + } + } + + private String processCookieHeader(HeaderElement element) { + String cookie = element.getName() + "=" + element.getValue(); + NameValuePair[] parameters = element.getParameters(); + for (int j = 0; parameters != null && j < parameters.length; j++) { + NameValuePair parameter = parameters[j]; + cookie = cookie + "; " + parameter.getName() + "=" + parameter.getValue(); + } + return cookie; + } + + protected void processResponse(HttpResponse response, MessageContext msgContext) + throws IOException { + obtainHTTPHeaderInformation(response, msgContext); + + HttpEntity httpEntity = response.getEntity(); + InputStream in = httpEntity.getContent(); + if (in == null) { + throw new AxisFault(Messages.getMessage("canNotBeNull", "InputStream")); + } + Header contentEncoding = httpEntity.getContentEncoding(); + if (contentEncoding != null) { + if (contentEncoding.getValue().equalsIgnoreCase(HTTPConstants.COMPRESSION_GZIP)) { + in = new GZIPInputStream(in); + // If the content-encoding is identity we can basically ignore + // it. + } else if (!"identity".equalsIgnoreCase(contentEncoding.getValue())) { + throw new AxisFault("HTTP :" + "unsupported content-encoding of '" + + contentEncoding.getValue() + "' found"); + } + } + + OperationContext opContext = msgContext.getOperationContext(); + if (opContext != null) { + opContext.setProperty(MessageContext.TRANSPORT_IN, in); + } + } + + /** + * getting host configuration to support standard http/s, proxy and NTLM + * support + * + * @param client active HttpClient + * @param msgCtx active MessageContext + * @param targetURL the target URL + * @return a HostConfiguration set up with proxy information + * @throws org.apache.axis2.AxisFault if problems occur + */ + protected HttpHost getHostConfiguration(AbstractHttpClient client, MessageContext msgCtx, + URL targetURL) throws AxisFault { + + boolean isAuthenticationEnabled = isAuthenticationEnabled(msgCtx); + int port = targetURL.getPort(); + + String protocol = targetURL.getProtocol(); + if (port == -1) { + if (HTTPTransportConstants.PROTOCOL_HTTP.equals(protocol)) { + port = 80; + } else if (HTTPTransportConstants.PROTOCOL_HTTPS.equals(protocol)) { + port = 443; + } + } + // to see the host is a proxy and in the proxy list - available in + // axis2.xml + HttpHost hostConfig = new HttpHost(targetURL.getHost(), port, targetURL.getProtocol()); + + // TODO : one might need to set his own socket factory. We have to allow that case as well. + + if (isAuthenticationEnabled) { + // Basic, Digest, NTLM and custom authentications. + this.setAuthenticationInfo(client, msgCtx); + } + // proxy configuration + + if (HTTPProxyConfigurator.isProxyEnabled(msgCtx, targetURL)) { + if (log.isDebugEnabled()) { + log.debug("Configuring HTTP proxy."); + } + HTTPProxyConfigurator.configure(msgCtx, client); + } + + return hostConfig; + } + + protected boolean isAuthenticationEnabled(MessageContext msgCtx) { + return (msgCtx.getProperty(HTTPConstants.AUTHENTICATE) != null); + } + + /* + * This will handle server Authentication, It could be either NTLM, Digest + * or Basic Authentication. Apart from that user can change the priory or + * add a custom authentication scheme. + */ + protected void setAuthenticationInfo(AbstractHttpClient agent, MessageContext msgCtx) + throws AxisFault { + HTTPAuthenticator authenticator; + Object obj = msgCtx.getProperty(HTTPConstants.AUTHENTICATE); + if (obj != null) { + if (obj instanceof HTTPAuthenticator) { + authenticator = (HTTPAuthenticator) obj; + + String username = authenticator.getUsername(); + String password = authenticator.getPassword(); + String host = authenticator.getHost(); + String domain = authenticator.getDomain(); + + int port = authenticator.getPort(); + String realm = authenticator.getRealm(); + + /* If retrying is available set it first */ + isAllowedRetry = authenticator.isAllowedRetry(); + + Credentials creds; + + // TODO : Set preemptive authentication, but its not recommended in HC 4 + + if (host != null) { + if (domain != null) { + /* Credentials for NTLM Authentication */ + //TODO : To enable NTLM we have to register the scheme with client, but it is available from 4.1 only +// agent.getAuthSchemes().register("ntlm",new NTLMSchemeFactory()); + creds = new NTCredentials(username, password, host, domain); + } else { + /* Credentials for Digest and Basic Authentication */ + creds = new UsernamePasswordCredentials(username, password); + } + agent.getCredentialsProvider(). + setCredentials(new AuthScope(host, port, realm), creds); + } else { + if (domain != null) { + /* + * Credentials for NTLM Authentication when host is + * ANY_HOST + */ + // TODO : Enable NTLM as metioned above + creds = new NTCredentials(username, password, AuthScope.ANY_HOST, domain); + agent.getCredentialsProvider(). + setCredentials(new AuthScope(AuthScope.ANY_HOST, port, realm), + creds); + } else { + /* Credentials only for Digest and Basic Authentication */ + creds = new UsernamePasswordCredentials(username, password); + agent.getCredentialsProvider(). + setCredentials(new AuthScope(AuthScope.ANY), creds); + } + } + /* Customizing the priority Order */ + List schemes = authenticator.getAuthSchemes(); + if (schemes != null && schemes.size() > 0) { + List authPrefs = new ArrayList(3); + for (int i = 0; i < schemes.size(); i++) { + if (schemes.get(i) instanceof AuthPolicy) { + authPrefs.add(schemes.get(i)); + continue; + } + String scheme = (String) schemes.get(i); + authPrefs.add(authenticator.getAuthPolicyPref(scheme)); + + } + // TODO : This is available in 4.1 only +// agent.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF, authPrefs); + } + + } else { + throw new AxisFault("HttpTransportProperties.Authenticator class cast exception"); + } + } + + } + + /** + * Method used to copy all the common properties + * + * @param msgContext - The messageContext of the request message + * @param url - The target URL + * @param httpMethod - The http method used to send the request + * @param httpClient - The httpclient used to send the request + * @param soapActionString - The soap action atring of the request message + * @return MessageFormatter - The messageFormatter for the relavent request + * message + * @throws org.apache.axis2.AxisFault - Thrown in case an exception occurs + */ + protected MessageFormatter populateCommonProperties(MessageContext msgContext, URL url, + HttpRequestBase httpMethod, + AbstractHttpClient httpClient, + String soapActionString) + throws AxisFault { + + if (isAuthenticationEnabled(msgContext)) { + httpMethod.getParams().setBooleanParameter(ClientPNames.HANDLE_AUTHENTICATION, true); + } + + MessageFormatter messageFormatter = TransportUtils.getMessageFormatter(msgContext); + + url = messageFormatter.getTargetAddress(msgContext, format, url); + + try { + httpMethod.setURI(url.toURI()); + } catch (URISyntaxException e) { + log.error("Error in URI : " + url, e); + } + + httpMethod.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, + messageFormatter.getContentType(msgContext, format, soapActionString)); + + httpMethod.setHeader(HTTPConstants.HEADER_HOST, url.getHost()); + + if (msgContext.getOptions() != null && msgContext.getOptions().isManageSession()) { + // setting the cookie in the out path + Object cookieString = msgContext.getProperty(HTTPConstants.COOKIE_STRING); + + if (cookieString != null) { + StringBuffer buffer = new StringBuffer(); + buffer.append(cookieString); + httpMethod.setHeader(HTTPConstants.HEADER_COOKIE, buffer.toString()); + } + } + + if (httpVersion.equals(HTTPConstants.HEADER_PROTOCOL_10)) { + httpClient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, + HttpVersion.HTTP_1_0); + } + return messageFormatter; + } + + /** + * This is used to get the dynamically set time out values from the message + * context. If the values are not available or invalid then the default + * values or the values set by the configuration will be used + * + * @param msgContext the active MessageContext + * @param httpClient + */ + protected void initializeTimeouts(MessageContext msgContext, AbstractHttpClient httpClient) { + // If the SO_TIMEOUT of CONNECTION_TIMEOUT is set by dynamically the + // override the static config + Integer tempSoTimeoutProperty = (Integer) msgContext.getProperty(HTTPConstants.SO_TIMEOUT); + Integer tempConnTimeoutProperty = (Integer) msgContext + .getProperty(HTTPConstants.CONNECTION_TIMEOUT); + long timeout = msgContext.getOptions().getTimeOutInMilliSeconds(); + + if (tempConnTimeoutProperty != null) { + int connectionTimeout = tempConnTimeoutProperty.intValue(); + // timeout for initial connection + httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, + connectionTimeout); + } else { + // set timeout in client + if (timeout > 0) { + httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, + (int) timeout); + } + } + + if (tempSoTimeoutProperty != null) { + int soTimeout = tempSoTimeoutProperty.intValue(); + // SO_TIMEOUT -- timeout for blocking reads + httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, soTimeout); + } else { + // set timeout in client + if (timeout > 0) { + httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, (int) timeout); + } + } + } + + /** + * This is used to get the dynamically set time out values from the message + * context. If the values are not available or invalid then the default + * values or the values set by the configuration will be used + * + * @param msgContext the active MessageContext + * @param httpMethod method + */ + protected void setTimeouts(MessageContext msgContext, HttpRequestBase httpMethod) { + // If the SO_TIMEOUT of CONNECTION_TIMEOUT is set by dynamically the + // override the static config + Integer tempSoTimeoutProperty = (Integer) msgContext.getProperty(HTTPConstants.SO_TIMEOUT); + Integer tempConnTimeoutProperty = (Integer) msgContext + .getProperty(HTTPConstants.CONNECTION_TIMEOUT); + long timeout = msgContext.getOptions().getTimeOutInMilliSeconds(); + + if (tempConnTimeoutProperty != null) { + // timeout for initial connection + httpMethod.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, + tempConnTimeoutProperty); + } + + if (tempSoTimeoutProperty != null) { + // SO_TIMEOUT -- timeout for blocking reads + httpMethod.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, + tempSoTimeoutProperty); + } else { + // set timeout in client + if (timeout > 0) { + httpMethod.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, (int) timeout); + } + } + } + + protected AbstractHttpClient getHttpClient(MessageContext msgContext) { + ConfigurationContext configContext = msgContext.getConfigurationContext(); + + AbstractHttpClient httpClient = (AbstractHttpClient) msgContext + .getProperty(HTTPConstants.CACHED_HTTP_CLIENT); + + if (httpClient == null) { + httpClient = (AbstractHttpClient) configContext. + getProperty(HTTPConstants.CACHED_HTTP_CLIENT); + } + + if (httpClient != null) { + return httpClient; + } + + synchronized (this) { + httpClient = (AbstractHttpClient) msgContext. + getProperty(HTTPConstants.CACHED_HTTP_CLIENT); + + if (httpClient == null) { + httpClient = (AbstractHttpClient) configContext + .getProperty(HTTPConstants.CACHED_HTTP_CLIENT); + } + + if (httpClient != null) { + return httpClient; + } + + ClientConnectionManager connManager = (ClientConnectionManager) msgContext + .getProperty(HTTPConstants.MULTITHREAD_HTTP_CONNECTION_MANAGER); + if (connManager == null) { + connManager = (ClientConnectionManager) msgContext + .getProperty(HTTPConstants.MULTITHREAD_HTTP_CONNECTION_MANAGER); + } + if (connManager == null) { + // reuse HttpConnectionManager + synchronized (configContext) { + connManager = (ClientConnectionManager) configContext + .getProperty(HTTPConstants.MULTITHREAD_HTTP_CONNECTION_MANAGER); + if (connManager == null) { + log.trace("Making new ConnectionManager"); + SchemeRegistry schemeRegistry = new SchemeRegistry(); + schemeRegistry.register( + new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + schemeRegistry.register( + new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); + + connManager = new ThreadSafeClientConnManager(new BasicHttpParams(), + schemeRegistry); + configContext.setProperty( + HTTPConstants.MULTITHREAD_HTTP_CONNECTION_MANAGER, connManager); + } + } + } + /* + * Create a new instance of HttpClient since the way it is used here + * it's not fully thread-safe. + */ + httpClient = new DefaultHttpClient(connManager, null); + + //We don't need to set timeout for connection manager, since we are doing it below + // and its enough + + // Get the timeout values set in the runtime + initializeTimeouts(msgContext, httpClient); + + return httpClient; + } + } + + protected HttpResponse executeMethod(AbstractHttpClient httpClient, MessageContext msgContext, + URL url, + HttpRequestBase method) throws IOException { + HttpHost httpHost = this.getHostConfiguration(httpClient, msgContext, url); + + // set the custom headers, if available + addCustomHeaders(method, msgContext); + + // add compression headers if needed + if (msgContext.isPropertyTrue(HTTPConstants.MC_ACCEPT_GZIP)) { + method.addHeader(HTTPConstants.HEADER_ACCEPT_ENCODING, + HTTPConstants.COMPRESSION_GZIP); + } + + if (msgContext.isPropertyTrue(HTTPConstants.MC_GZIP_REQUEST)) { + method.addHeader(HTTPConstants.HEADER_CONTENT_ENCODING, + HTTPConstants.COMPRESSION_GZIP); + } + + if (msgContext.getProperty(HTTPConstants.HTTP_METHOD_PARAMS) != null) { + HttpParams params = (HttpParams) msgContext + .getProperty(HTTPConstants.HTTP_METHOD_PARAMS); + method.setParams(params); + } + + String cookiePolicy = (String) msgContext.getProperty(HTTPConstants.COOKIE_POLICY); + if (cookiePolicy != null) { + method.getParams().setParameter(ClientPNames.COOKIE_POLICY, cookiePolicy); + } + + setTimeouts(msgContext, method); + HttpContext localContext = new BasicHttpContext(); + // Why do we have add context here + return httpClient.execute(httpHost, method, localContext); + } + + public void addCustomHeaders(HttpRequestBase method, MessageContext msgContext) { + + boolean isCustomUserAgentSet = false; + // set the custom headers, if available + Object httpHeadersObj = msgContext.getProperty(HTTPConstants.HTTP_HEADERS); + if (httpHeadersObj != null) { + if (httpHeadersObj instanceof List) { + List httpHeaders = (List) httpHeadersObj; + for (int i = 0; i < httpHeaders.size(); i++) { + NamedValue nv = (NamedValue) httpHeaders.get(i); + if (nv != null) { + Header header = new BasicHeader(nv.getName(), nv.getValue()); + if (HTTPConstants.HEADER_USER_AGENT.equals(header.getName())) { + isCustomUserAgentSet = true; + } + method.addHeader(header); + } + } + + } + if (httpHeadersObj instanceof Map) { + Map httpHeaders = (Map) httpHeadersObj; + for (Iterator iterator = httpHeaders.entrySet().iterator(); iterator.hasNext(); ) { + Map.Entry entry = (Map.Entry) iterator.next(); + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + if (HTTPConstants.HEADER_USER_AGENT.equals(key)) { + isCustomUserAgentSet = true; + } + method.addHeader(key, value); + } + } + } + + // we have to consider the TRANSPORT_HEADERS map as well + Map transportHeaders = (Map) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS); + if (transportHeaders != null) { + removeUnwantedHeaders(msgContext); + + Set headerEntries = transportHeaders.entrySet(); + + for (Object headerEntry : headerEntries) { + if (headerEntry instanceof Map.Entry) { + Header[] headers = method.getAllHeaders(); + + boolean headerAdded = false; + for (Header header : headers) { + if (header.getName() != null + && header.getName().equals(((Map.Entry) headerEntry).getKey())) { + headerAdded = true; + break; + } + } + + if (!headerAdded) { + method.addHeader(((Map.Entry) headerEntry).getKey().toString(), + ((Map.Entry) headerEntry).getValue().toString()); + } + } + } + } + + if (!isCustomUserAgentSet) { + String userAgentString = getUserAgent(msgContext); + method.setHeader(HTTPConstants.HEADER_USER_AGENT, userAgentString); + } + + } + + /** + * Remove unwanted headers from the transport headers map of outgoing + * request. These are headers which should be dictated by the transport and + * not the user. We remove these as these may get copied from the request + * messages + * + * @param msgContext the Axis2 Message context from which these headers should be + * removed + */ + private void removeUnwantedHeaders(MessageContext msgContext) { + Map headers = (Map) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS); + + if (headers == null || headers.isEmpty()) { + return; + } + + Iterator iter = headers.keySet().iterator(); + while (iter.hasNext()) { + String headerName = (String) iter.next(); + if (HTTP.CONN_DIRECTIVE.equalsIgnoreCase(headerName) + || HTTP.TRANSFER_ENCODING.equalsIgnoreCase(headerName) + || HTTP.DATE_HEADER.equalsIgnoreCase(headerName) + || HTTP.CONTENT_TYPE.equalsIgnoreCase(headerName) + || HTTP.CONTENT_LEN.equalsIgnoreCase(headerName)) { + iter.remove(); + } + } + } + + private String getUserAgent(MessageContext messageContext) { + String userAgentString = "Axis2"; + boolean locked = false; + if (messageContext.getParameter(HTTPConstants.USER_AGENT) != null) { + OMElement userAgentElement = messageContext.getParameter(HTTPConstants.USER_AGENT) + .getParameterElement(); + userAgentString = userAgentElement.getText().trim(); + OMAttribute lockedAttribute = userAgentElement.getAttribute(new QName("locked")); + if (lockedAttribute != null) { + if (lockedAttribute.getAttributeValue().equalsIgnoreCase("true")) { + locked = true; + } + } + } + // Runtime overing part + if (!locked) { + if (messageContext.getProperty(HTTPConstants.USER_AGENT) != null) { + userAgentString = (String) messageContext.getProperty(HTTPConstants.USER_AGENT); + } + } + + return userAgentString; + } + +} diff --git a/modules/transport/http/test/org/apache/axis2/transport/http/HTTPClient4SenderTest.java b/modules/transport/http/test/org/apache/axis2/transport/http/HTTPClient4SenderTest.java new file mode 100644 index 0000000..a7c697b --- /dev/null +++ b/modules/transport/http/test/org/apache/axis2/transport/http/HTTPClient4SenderTest.java @@ -0,0 +1,178 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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.axis2.transport.http; + +import org.apache.axis2.Constants; +import org.apache.axis2.transport.http.impl.httpclient4.HTTPSenderImpl; + +import javax.ws.rs.core.HttpHeaders; + +public class HTTPClient4SenderTest extends HTTPSenderTest { + + @Override + protected HTTPSender getHTTPSender() { + return new HTTPSenderImpl(); + } + + @Override + public void testSendViaGet() throws Exception { + int port = getBasicHttpServer().getPort(); + sendViaHTTP(Constants.Configuration.HTTP_METHOD_GET, "urn:getService", "http://localhost:" + + port + "/getService", true); + assertEquals("Not the expected HTTP Method", Constants.Configuration.HTTP_METHOD_GET, + getHTTPMethod()); + assertEquals("Not the expected content", "/getService?part=sample%20data", + getStringContent()); + assertEquals("Not the expected HTTP Header value", "urn:getService", + getHeaders().get("SOAPAction")); + assertEquals("Not the expected HTTP Header value", + "application/x-www-form-urlencoded;action=\"urn:getService\";", + getHeaders().get(HttpHeaders.CONTENT_TYPE)); + assertEquals("Not the expected HTTP Header value", "localhost", + getHeaders().get(HttpHeaders.HOST)); + assertEquals("Not the expected HTTP Header value", "Axis2", + getHeaders().get(HttpHeaders.USER_AGENT)); + } + + @Override + public void testSendViaPost() throws Exception { + // test with REST payload + int port = getBasicHttpServer().getPort(); + sendViaHTTP(Constants.Configuration.HTTP_METHOD_POST, "urn:postService", + "http://localhost:" + port + "/postService", true); + assertEquals("Not the expected HTTP Method", Constants.Configuration.HTTP_METHOD_POST, + getHTTPMethod()); + assertEquals("Not the expected content", getEnvelope().getFirstElement().getFirstElement() + .toString(), getStringContent()); + assertEquals("Not the expected HTTP Header value", "urn:postService", + getHeaders().get("SOAPAction")); + assertEquals("Not the expected HTTP Header value", "application/xml", + getHeaders().get(HttpHeaders.CONTENT_TYPE)); + assertEquals("Not the expected HTTP Header value", "localhost", + getHeaders().get(HttpHeaders.HOST)); + assertEquals("Not the expected HTTP Header value", "Axis2", + getHeaders().get(HttpHeaders.USER_AGENT)); + + // test with SOAP payload. + sendViaHTTP(Constants.Configuration.HTTP_METHOD_POST, "urn:postService", + "http://localhost:" + port + "/postService", false); + assertEquals("Not the expected HTTP Method", Constants.Configuration.HTTP_METHOD_POST, + getHTTPMethod()); + assertEquals("Not the expected content", getEnvelope().toString(), getStringContent()); + assertEquals("Not the expected HTTP Header value", "urn:postService", + getHeaders().get("SOAPAction").replace("\"", "")); + assertEquals("Not the expected HTTP Header value", "text/xml", + getHeaders().get(HttpHeaders.CONTENT_TYPE)); + assertEquals("Not the expected HTTP Header value", "localhost", + getHeaders().get(HttpHeaders.HOST)); + assertEquals("Not the expected HTTP Header value", "Axis2", + getHeaders().get(HttpHeaders.USER_AGENT)); + } + + @Override + public void testSendViaPut() throws Exception { + // test with REST payload + int port = getBasicHttpServer().getPort(); + sendViaHTTP(Constants.Configuration.HTTP_METHOD_PUT, "urn:putService", "http://localhost:" + + port + "/putService", true); + assertEquals("Not the expected HTTP Method", Constants.Configuration.HTTP_METHOD_PUT, + getHTTPMethod()); + assertEquals("Not the expected content", getEnvelope().getFirstElement().getFirstElement() + .toString(), getStringContent()); + assertEquals("Not the expected HTTP Header value", "urn:putService", + getHeaders().get("SOAPAction")); + assertEquals("Not the expected HTTP Header value", "application/xml", + getHeaders().get(HttpHeaders.CONTENT_TYPE)); + assertEquals("Not the expected HTTP Header value", "localhost", + getHeaders().get(HttpHeaders.HOST)); + assertEquals("Not the expected HTTP Header value", "Axis2", + getHeaders().get(HttpHeaders.USER_AGENT)); + + // test with SOAP payload. + sendViaHTTP(Constants.Configuration.HTTP_METHOD_PUT, "urn:putService", "http://localhost:" + + port + "/putService", false); + assertEquals("Not the expected HTTP Method", Constants.Configuration.HTTP_METHOD_PUT, + getHTTPMethod()); + assertEquals("Not the expected content", getEnvelope().toString(), getStringContent()); + assertEquals("Not the expected HTTP Header value", "urn:putService", + getHeaders().get("SOAPAction").replace("\"", "")); + assertEquals("Not the expected HTTP Header value", "text/xml", + getHeaders().get(HttpHeaders.CONTENT_TYPE)); + assertEquals("Not the expected HTTP Header value", "localhost", + getHeaders().get(HttpHeaders.HOST)); + assertEquals("Not the expected HTTP Header value", "Axis2", + getHeaders().get(HttpHeaders.USER_AGENT)); + } + + @Override + public void testSendViaDelete() throws Exception { + // test with REST payload + int port = getBasicHttpServer().getPort(); + sendViaHTTP(Constants.Configuration.HTTP_METHOD_DELETE, "urn:deleteService", + "http://localhost:" + port + "/deleteService", true); + assertEquals("Not the expected HTTP Method", Constants.Configuration.HTTP_METHOD_DELETE, + getHTTPMethod()); + assertEquals("Not the expected content", "/deleteService?part=sample%20data", + getStringContent()); + assertEquals("Not the expected HTTP Header value", + "application/x-www-form-urlencoded;action=\"urn:deleteService\";", getHeaders() + .get(HttpHeaders.CONTENT_TYPE)); + assertEquals("Not the expected HTTP Header value", "localhost", + getHeaders().get(HttpHeaders.HOST)); + assertEquals("Not the expected HTTP Header value", "Axis2", + getHeaders().get(HttpHeaders.USER_AGENT)); + } + + @Override + public void testSendViaHead() throws Exception { + int port = getBasicHttpServer().getPort(); + sendViaHTTP(Constants.Configuration.HTTP_METHOD_HEAD, "urn:deleteService", + "http://localhost:" + port + "/deleteService", true); + assertEquals("Not the expected HTTP Method", Constants.Configuration.HTTP_METHOD_POST, + getHTTPMethod()); + assertEquals("Not the expected content", getEnvelope().getFirstElement().getFirstElement() + .toString(), getStringContent()); + assertEquals("Not the expected HTTP Header value", "application/xml", + getHeaders().get(HttpHeaders.CONTENT_TYPE)); + assertEquals("Not the expected HTTP Header value", "localhost", + getHeaders().get(HttpHeaders.HOST)); + assertEquals("Not the expected HTTP Header value", "Axis2", + getHeaders().get(HttpHeaders.USER_AGENT)); + + } + + @Override + public void testSendNOHTTPMethod() throws Exception { + int port = getBasicHttpServer().getPort(); + sendViaHTTP(null, "urn:noService", "http://localhost:" + port + "/noService", true); + assertEquals("Not the expected HTTP Method", Constants.Configuration.HTTP_METHOD_POST, + getHTTPMethod()); + assertEquals("Not the expected content", getEnvelope().getFirstElement().getFirstElement() + .toString(), getStringContent()); + assertEquals("Not the expected HTTP Header value", "urn:noService", + getHeaders().get("SOAPAction")); + assertEquals("Not the expected HTTP Header value", "application/xml", + getHeaders().get(HttpHeaders.CONTENT_TYPE)); + assertEquals("Not the expected HTTP Header value", "localhost", + getHeaders().get(HttpHeaders.HOST)); + assertEquals("Not the expected HTTP Header value", "Axis2", + getHeaders().get(HttpHeaders.USER_AGENT)); + } +} diff --git a/modules/transport/http/test/org/apache/axis2/transport/http/HTTPSenderTest.java b/modules/transport/http/test/org/apache/axis2/transport/http/HTTPSenderTest.java index d51b28d..96691d4 100644 --- a/modules/transport/http/test/org/apache/axis2/transport/http/HTTPSenderTest.java +++ b/modules/transport/http/test/org/apache/axis2/transport/http/HTTPSenderTest.java @@ -19,12 +19,6 @@ package org.apache.axis2.transport.http; -import java.io.IOException; -import java.net.URL; - -import javax.mail.MessagingException; -import javax.ws.rs.core.HttpHeaders; - import org.apache.axis2.Constants; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; @@ -33,6 +27,11 @@ import org.apache.axis2.context.OperationContext; import org.apache.axis2.transport.http.mock.server.AbstractHTTPServerTest; import org.apache.axis2.transport.http.mock.server.BasicHttpServer; +import javax.mail.MessagingException; +import javax.ws.rs.core.HttpHeaders; +import java.io.IOException; +import java.net.URL; + /** * The Class HTTPSenderTest. */ @@ -58,7 +57,7 @@ public abstract class HTTPSenderTest extends AbstractHTTPServerTest { * @throws MessagingException * the messaging exception */ - private void sendViaHTTP(String httpMethod, String soapAction, String address, boolean rest) + protected void sendViaHTTP(String httpMethod, String soapAction, String address, boolean rest) throws IOException, MessagingException { httpSender = getHTTPSender(); MessageContext msgContext = new MessageContext();