You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yacy_search_server/source/de/anomic/soap/httpdSoapHandler.java

780 lines
33 KiB

//httpdSoapHandler.java
//------------------------
//part of YaCy
//(C) by Michael Peter Christen; mc@anomic.de
//first published on http://www.anomic.de
//Frankfurt, Germany, 2005
//
//this file was contributed by Martin Thelian
//last major change: $LastChangedDate$ by $LastChangedBy$
//Revision: $LastChangedRevision$
//
//This program is free software; you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation; either version 2 of the License, or
//(at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//Using this software in any meaning (reading, learning, copying, compiling,
//running) means that you agree that the Author(s) is (are) not responsible
//for cost, loss of data or any harm that may be caused directly or indirectly
//by usage of this softare or this documentation. The usage of this software
//is on your own risk. The installation and usage (starting/running) of this
//software may allow other people or application to access your computer and
//any attached devices and is highly dependent on the configuration of the
//software which must be done by the user of the software; the author(s) is
//(are) also not responsible for proper configuration and usage of the
//software, even if provoked by documentation provided together with
//the software.
//
//Any changes to this file according to the GPL as documented in the file
//gpl.txt aside this file in the shipment you received can be done to the
//lines that follows this copyright notice here, but changes must not be
//done inside the copyright notive above. A re-distribution must contain
//the intact and unchanged copyright notice.
//Contributions and changes to the program code must be marked as such.
package de.anomic.soap;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Properties;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.SOAPException;
import org.apache.axis.AxisFault;
import org.apache.axis.EngineConfiguration;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.WSDDEngineConfiguration;
import org.apache.axis.configuration.FileProvider;
import org.apache.axis.deployment.wsdd.WSDDDeployment;
import org.apache.axis.deployment.wsdd.WSDDDocument;
import org.apache.axis.server.AxisServer;
import org.apache.axis.utils.XMLUtils;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import de.anomic.http.httpChunkedInputStream;
import de.anomic.http.httpChunkedOutputStream;
import de.anomic.http.httpContentLengthInputStream;
import de.anomic.http.httpHeader;
import de.anomic.http.httpd;
import de.anomic.http.httpdAbstractHandler;
import de.anomic.http.httpdHandler;
import de.anomic.plasma.plasmaParser;
import de.anomic.server.serverClassLoader;
import de.anomic.server.serverCore;
import de.anomic.server.serverFileUtils;
import de.anomic.server.serverObjects;
import de.anomic.server.serverSwitch;
import de.anomic.server.logging.serverLog;
/**
* Class to accept SOAP Requests and invoke the desired soapService.
* An example how to do a soap call from php:
* <code>
* <?php
* $client = new SoapClient("http://192.168.1.201:8080/soap/index?wsdl", array(
* "trace" => 1,
* "exceptions" => 1));
*
* try
* {
* $result = $client->__call("crawling", array("http://test.at"), NULL,
* new SoapHeader("http://http.anomic.de/header", "Authorization", md5(base64_encode("admin:xxxxxxx"))));
* }
* catch (SoapFault $fault)
* {
* $result = $fault->faultstring;
* }
*
* print($result);
* ?>
* </code>
*
*
*
* @author Martin Thelian
*/
public final class httpdSoapHandler extends httpdAbstractHandler implements httpdHandler
{
public static final String SOAP_HANDLER_VERSION = "YaCySOAP V0.1";
/* ===============================================================
* Constants needed to set some SOAP properties
* =============================================================== */
/**
* SOAP Header Namespace needed to access the soap header field containing
* the user authentication
*/
public static final String serviceHeaderNamespace = "http://http.anomic.de/header";
/**
* define the needed deployment strings
*/
public static final String serviceDeploymentString =
"<deployment "
+ "xmlns=\"http://xml.apache.org/axis/wsdd/\" "
+ "xmlns:java=\"http://xml.apache.org/axis/wsdd/providers/java\" >"
+ "<service name=\"@serviceName@\" provider=\"java:RPC\">"
+ "<parameter name=\"typeMappingVersion\" value=\"1.1\"/>"
+ "<parameter name=\"scope\" value=\"Request\"/>"
+ "<parameter name=\"className\" value=\"@className@\" />"
+ "<parameter name=\"allowedMethods\" value=\"*\" />"
+ "</service>"
+ "</deployment>";
private static final String[] defaultServices = new String[] {
"search=de.anomic.soap.services.SearchService",
"crawl=de.anomic.soap.services.CrawlService",
"status=de.anomic.soap.services.StatusService",
"admin=de.anomic.soap.services.AdminService",
"blacklist=de.anomic.soap.services.BlacklistService",
"share=de.anomic.soap.services.ShareService",
"bookmarks=de.anomic.soap.services.BookmarkService",
"messages=de.anomic.soap.services.MessageService"
};
/* ===============================================================
* Constants needed to set the SOAP message context
* =============================================================== */
/**
* CONSTANT: tge server switchboard
*/
public static final String MESSAGE_CONTEXT_SERVER_SWITCH = "serverSwitch";
/**
* CONSTANT: received http headers
*/
public static final String MESSAGE_CONTEXT_HTTP_HEADER = "httpHeader";
/**
* CONSTANT: soap utility class
*/
public static final String MESSAGE_CONTEXT_SERVER_CONTEXT = "serverContext";
/* ===============================================================
* Other object fields
* =============================================================== */
private static final Object initSync = new Object();
private serverClassLoader provider = null;
private HashMap templates;
private serverSwitch switchboard;
private static AxisServer engine = null;
private File htRootPath;
private File htTemplatePath;
private static Properties additionalServices = null;
/**
* Constructor of this class
* @param theSwitchboard
* @throws Exception
*/
public httpdSoapHandler(serverSwitch theSwitchboard) throws Exception {
super();
this.switchboard = theSwitchboard;
this.theLogger = new serverLog("SOAP");
// create a htRootPath: system pages
if (this.htRootPath == null) {
this.htRootPath = new File(this.switchboard.getRootPath(), this.switchboard.getConfig("htRootPath","htroot"));
// if (!(htRootPath.exists())) htRootPath.mkdir();
}
if (this.htTemplatePath == null) {
this.htTemplatePath = new File(theSwitchboard.getRootPath(), theSwitchboard.getConfig("htTemplatePath","htroot/env/templates"));
// if (!(this.htTemplatePath.exists())) this.htTemplatePath.mkdir();
}
if (this.provider == null) {
this.provider = new serverClassLoader(/*this.getClass().getClassLoader()*/);
}
if (this.templates == null) {
this.templates = loadTemplates(this.htTemplatePath);
}
// deploy default soap services
if (engine == null) synchronized (initSync) { deployDefaultServices(); }
// init additional soap services
if (additionalServices == null) synchronized (initSync) { deployAdditionalServices(); }
}
private void deployDefaultServices() throws Exception {
try {
// testing if a security manager is active.
SecurityManager sm = System.getSecurityManager();
this.theLogger.logInfo("Security Manager is: " + ((sm==null)?"not ":"") + "active");
// create an Axis server
this.theLogger.logInfo("Init soap engine ...");
engine = new AxisServer(new FileProvider("server-config.wsdd"));
// setting some options ...
engine.setShouldSaveConfig(false);
} catch (Exception e) {
this.theLogger.logSevere("Unable to initialize soap engine",e);
throw e;
} catch (Error e) {
this.theLogger.logSevere("Unable to initialize soap engine",e);
throw e;
}
try {
this.theLogger.logInfo("Deploying default services ...");
for (int i=0; i < defaultServices.length; i++) {
String[] nextService = defaultServices[i].split("=");
this.theLogger.logInfo("Deploying service " + nextService[0] + ": " + nextService[1]);
String deploymentStr = serviceDeploymentString
.replaceAll("@serviceName@", nextService[0])
.replaceAll("@className@", nextService[1]);
// deploy the service
deployService(deploymentStr,engine);
}
} catch (Exception e) {
this.theLogger.logSevere("Unable to deploy default soap services.",e);
throw e;
} catch (Error e) {
this.theLogger.logSevere("Unable to deploy default soap services.",e);
throw e;
}
}
private void deployAdditionalServices() {
additionalServices = new Properties();
// getting the property filename containing the file list
String fileName = this.switchboard.getConfig("soap.serviceDeploymentList","");
if (fileName.length() > 0) {
BufferedInputStream fileInput = null;
try {
File deploymentFile = new File(this.switchboard.getRootPath(),fileName);
fileInput = new BufferedInputStream(new FileInputStream(deploymentFile));
// load property list
additionalServices.load(fileInput);
fileInput.close();
// loop through and deploy services
if (additionalServices.size() > 0) {
Enumeration serviceNameEnum = additionalServices.keys();
while (serviceNameEnum.hasMoreElements()) {
String serviceName = (String) serviceNameEnum.nextElement();
String className = additionalServices.getProperty(serviceName);
String deploymentStr = serviceDeploymentString
.replaceAll("@serviceName@", serviceName)
.replaceAll("@className@", className);
// deploy the service
deployService(deploymentStr,engine);
}
}
} catch (Exception e) {
this.theLogger.logSevere("Unable to deploy additional services: " + e.getMessage(), e);
} finally {
if (fileInput != null) try { fileInput.close(); } catch (Exception e){/* ignore this */}
}
}
}
private InputStream getBodyInputStream(httpHeader requestHeader, PushbackInputStream body) throws SoapException{
InputStream input;
// getting the content length
long contentLength = requestHeader.contentLength();
String transferEncoding = (String) requestHeader.get(httpHeader.TRANSFER_ENCODING);
String contentEncoding = (String) requestHeader.get(httpHeader.CONTENT_ENCODING);
/* ===========================================================================
* Handle TRANSFER ENCODING
* =========================================================================== */
if (transferEncoding != null && !transferEncoding.equalsIgnoreCase("identity")) {
// read using transfer encoding
if (transferEncoding.equalsIgnoreCase("chunked")) {
input = new httpChunkedInputStream(body);
} else {
String errorMsg = "Unsupported transfer-encoding: "+ transferEncoding;
this.theLogger.logSevere(errorMsg);
throw new SoapException(501,"Not Implemented",errorMsg);
}
} else if (contentLength > 0) {
// read contentLength bytes
input = new httpContentLengthInputStream(body,contentLength);
} else {
// read until EOF
input = body;
}
/* ===========================================================================
* Handle CONTENT ENCODING
* =========================================================================== */
try {
if (contentEncoding != null && !contentEncoding.equals("identity")) {
if (contentEncoding.equalsIgnoreCase(httpHeader.CONTENT_ENCODING_GZIP)) {
input = new GZIPInputStream(input);
} else {
String errorMsg = "Unsupported content encoding: " + contentEncoding;
this.theLogger.logSevere(errorMsg);
throw new SoapException(415,"Unsupported Media Type",errorMsg);
}
}
} catch (IOException e) {
throw new SoapException(400,"Bad Request",e);
}
return input;
}
/**
* HTTP HEAD method. Not needed for soap.
* @param conProp
* @param header
* @param response
* @throws IOException
*
* @see de.anomic.http.httpdHandler#doHead(java.util.Properties, de.anomic.http.httpHeader, java.io.OutputStream)
*/
public void doHead(Properties conProp, httpHeader requestHeader, OutputStream clientOut) throws IOException {
sendMessage(conProp, requestHeader, clientOut, 501, "Not Implemented", "Connection method is not supported by this handler",null);
conProp.setProperty(httpHeader.CONNECTION_PROP_PERSISTENT,"close");
}
/**
* HTTP Connect Method. Not needed for SOAP
* @param conProp
* @param requestHeader
* @param clientIn
* @param clientOut
* @throws IOException
*
* @see de.anomic.http.httpdHandler#doConnect(java.util.Properties, de.anomic.http.httpHeader, java.io.InputStream, java.io.OutputStream)
*/
public void doConnect(Properties conProp, httpHeader requestHeader, InputStream clientIn, OutputStream clientOut) throws IOException {
sendMessage(conProp, requestHeader, clientOut, 501, "Not Implemented", "Connection method is not supported by this handler",null);
conProp.setProperty(httpHeader.CONNECTION_PROP_PERSISTENT,"close");
}
/**
* Handle http-GET requests. For soap this is usually a query for the wsdl-file.
* Therefore we always return the wsdl file for a get request
*
* @param conProp
* @param requestHeader all received http headers
* @param response {@link OutputStream} to the client
*
* @throws IOException
*
* @see de.anomic.http.httpdHandler#doGet(java.util.Properties, de.anomic.http.httpHeader, java.io.OutputStream)
*/
public void doGet(Properties conProp, httpHeader requestHeader, OutputStream response) throws IOException {
MessageContext msgContext = null;
String path = conProp.getProperty(httpHeader.CONNECTION_PROP_PATH);
try {
// generating message context
msgContext = this.generateMessageContext(path, requestHeader, conProp);
if (path.equals("/soap/")) {
serverObjects args = new serverObjects();
args.put("SOAP.engine",httpdSoapHandler.engine);
ServerContext sContext = (ServerContext) msgContext.getProperty(MESSAGE_CONTEXT_SERVER_CONTEXT);
byte[] result = sContext.writeTemplate("soap/ServiceList.html", args, requestHeader);
sendMessage(conProp, requestHeader, response, 200, "OK", "text/html; charset=utf-8", result);
} else if (path.equals("/soap/favicon.ico")) {
sendMessage(conProp, requestHeader, response, 404, "File not found", "text/plain",null);
} else {
// generating wsdl file
Document doc = generateWSDL(msgContext);
if (doc != null) {
// TODO: what about doc.getInputEncoding()?
// TODO: what about getXmlEncoding?
// Converting the the wsdl document into a byte-array
String responseDoc = XMLUtils.DocumentToString(doc);
byte[] result = responseDoc.getBytes("UTF-8");
// send back the result
sendMessage(conProp, requestHeader, response, 200, "OK", "text/xml; charset=utf-8", result);
if (!(requestHeader.get(httpHeader.CONNECTION, "close").equals("keep-alive"))) {
// wait a little time until everything closes so that clients can read from the streams/sockets
try {Thread.currentThread().join(200);} catch (InterruptedException e) {/* ignore this */}
}
} else {
// if we where unable to generate the wsdl file ....
String errorMsg = "Internal Server Error: Unable to generate the WSDL file.";
sendMessage(conProp, requestHeader, response, 500, "Internal Error", "text/plain",errorMsg.getBytes("UTF-8"));
}
}
return;
} catch (Exception e) {
// handle error
handleException(conProp,requestHeader,msgContext,response,e);
}
}
/**
* HTTP Post method. Needed to call a soap service on this server from a soap client
* @param conProp the connection properties
* @param requestHeader the received http headers
* @param response {@link OutputStream} to the client
* @param body the request body containing the SOAP message
*
* @see de.anomic.http.httpdHandler#doPost(java.util.Properties, de.anomic.http.httpHeader, java.io.OutputStream, java.io.PushbackInputStream)
*/
public void doPost(Properties conProp, httpHeader requestHeader, OutputStream response, PushbackInputStream body) {
MessageContext msgContext = null;
String path = conProp.getProperty(httpHeader.CONNECTION_PROP_PATH);
try {
/* ========================================================================
* GENERATE REQUEST MESSAGE
* ======================================================================== */
// read the request message
InputStream bodyStream = getBodyInputStream(requestHeader, body);
// generating the SOAP message context that will be passed over to the invoked service
msgContext = this.generateMessageContext(path, requestHeader, conProp);
// Generating a SOAP Request Message Object
String mime = plasmaParser.getRealMimeType(requestHeader.mime()); // this is important !!!!
Message requestMsg = new Message(
bodyStream,
false,
mime,
(String)requestHeader.get(httpHeader.CONTENT_LOCATION)
);
msgContext.setRequestMessage(requestMsg);
/* ========================================================================
* SERVICE INVOCATION
* ======================================================================== */
Message responseMsg = this.invokeService(msgContext);
if (responseMsg != null) {
sendMessage(conProp, requestHeader, response, 200, "OK", responseMsg);
} else {
sendMessage(conProp, requestHeader, response, 202, "Accepted", "text/plain", null);
}
return;
} catch (Exception e) {
// handle error
handleException(conProp, requestHeader, msgContext, response,e);
}
}
private void handleException(Properties conProp, httpHeader requestHeader, MessageContext messageContext, OutputStream response, Exception e) {
try {
Message soapErrorMsg = null;
if (!conProp.containsKey(httpHeader.CONNECTION_PROP_PROXY_RESPOND_HEADER)) {
// if no header was send until now we can send back an error message
SoapException soapEx = null;
if (!(e instanceof SoapException)) {
soapEx = new SoapException(500,"internal server error",e);
} else {
soapEx = (SoapException) e;
}
// generating a soap error message
soapErrorMsg = soapEx.getFaultMessage(messageContext);
// send error message back to the client
sendMessage(conProp,requestHeader,response,soapEx.getStatusCode(),soapEx.getStatusText(),soapErrorMsg);
} else {
this.theLogger.logSevere("Unexpected Exception while sending data to client",e);
}
} catch (Exception ex) {
// the http response header was already send. Just log the error
this.theLogger.logSevere("Unexpected Exception while sending error message",e);
} finally {
// force connection close
conProp.setProperty(httpHeader.CONNECTION_PROP_PERSISTENT,"close");
}
}
private Document generateWSDL(MessageContext msgContext) throws SoapException {
try {
engine.generateWSDL(msgContext);
Document doc = (Document) msgContext.getProperty("WSDL");
return doc;
} catch (Exception ex) {
if (ex instanceof AxisFault) throw new SoapException((AxisFault)ex);
throw new SoapException(500,"Unable to generate WSDL",ex);
}
}
protected Message invokeService(MessageContext msgContext) throws SoapException {
try {
// invoke the service
engine.invoke(msgContext);
// Retrieve the response from Axis
return msgContext.getResponseMessage();
} catch (Exception ex) {
if (ex instanceof AxisFault) throw new SoapException((AxisFault)ex);
throw new SoapException(500,"Unable to invoke service",ex);
}
}
/**
* This function deplays all java classes that should be available via SOAP call.
*
* @param deploymentString the deployment string containing detailed information about
* the java class that should be deployed
* @param theAxisServer the apache axis engine where the service should be deployed
*
* @return <code>true</code> if the deployment was done successfully or <code>false</code>
* otherwise
*/
private static boolean deployService(String deploymentString, AxisServer theAxisServer)
{
// convert WSDD file string into bytestream for furhter processing
InputStream deploymentStream = null;
if (deploymentString != null) {
deploymentStream = new ByteArrayInputStream(deploymentString.getBytes());
Document root = null;
try {
// build XML document from stream
root = XMLUtils.newDocument(deploymentStream);
// parse WSDD file
WSDDDocument wsddDoc = new WSDDDocument(root);
// get the configuration of this axis engine
EngineConfiguration config = theAxisServer.getConfig();
if (config instanceof WSDDEngineConfiguration) {
// get the current configuration of the Axis engine
WSDDDeployment deploymentWSDD =
((WSDDEngineConfiguration) config).getDeployment();
// undeply unneeded standard services
deploymentWSDD.undeployService(new QName("Version"));
deploymentWSDD.undeployService(new QName("AdminService"));
// deploy the new service
// an existing service with the same name gets deleted
wsddDoc.deploy(deploymentWSDD);
}
} catch (ParserConfigurationException e) {
System.err.println("Could not deploy service.");
return false;
} catch (SAXException e) {
System.err.println("Could not deploy service.");
return false;
} catch (IOException e) {
System.err.println("Could not deploy service.");
return false;
}
} else {
System.err.println("Service deployment string is NULL! SOAP Service not deployed.");
return false;
}
return true;
}
/**
* This function is used to generate the SOAP Message Context that is handed over to
* the called service.
* This message context contains some fields needed by the service to fullfil the request.
*
* @param path the path of the request
* @param requestHeader the http headers of the request
* @param conProps TODO
* @return the generated {@link MessageContext}
* @throws SoapException
*
* @throws Exception if the {@link MessageContext} could not be generated successfully.
*/
private MessageContext generateMessageContext(String path, httpHeader requestHeader, Properties conProps) throws SoapException {
try {
// getting the requestes service name
String serviceName = path.substring("/soap/".length());
// create and initialize a message context
MessageContext msgContext = new MessageContext(httpdSoapHandler.engine);
msgContext.setTransportName("YaCy-SOAP");
msgContext.setProperty(MessageContext.TRANS_URL, "http://" + requestHeader.get(httpHeader.HOST) + ((((String)requestHeader.get(httpHeader.HOST)).indexOf(":") > -1)?"":Integer.toString(serverCore.getPortNr(this.switchboard.getConfig("port","8080")))) +
"/soap/" + serviceName);
// the used http verson
String version = conProps.getProperty(httpHeader.CONNECTION_PROP_HTTP_VER);
msgContext.setProperty(MessageContext.HTTP_TRANSPORT_VERSION,version);
// generate the serverContext object
ServerContext serverContext = new ServerContext(this.htRootPath.toString(),this.provider,this.templates,this.switchboard);
msgContext.setProperty(MESSAGE_CONTEXT_SERVER_CONTEXT ,serverContext);
// YaCy specific objects
msgContext.setProperty(MESSAGE_CONTEXT_SERVER_SWITCH,this.switchboard);
msgContext.setProperty(MESSAGE_CONTEXT_HTTP_HEADER ,requestHeader);
// setting the service to execute
msgContext.setTargetService(serviceName);
return msgContext;
} catch (Exception e) {
if (e instanceof AxisFault) throw new SoapException((AxisFault)e);
throw new SoapException(500,"Unable to generate message context",e);
}
}
/**
* This method was copied from {@link httpdFileHandler}. Maybe it would be a good idea
* to move this function up into {@link httpdAbstractHandler}
*
* @param path the path to the template dir
* @return a hasmap containing all templates
*/
private static HashMap loadTemplates(File path) {
// reads all templates from a path
// we use only the folder from the given file path
HashMap result = new HashMap();
if (path == null) return result;
if (!(path.isDirectory())) path = path.getParentFile();
if ((path == null) || (!(path.isDirectory()))) return result;
String[] templates = path.list();
for (int i = 0; i < templates.length; i++) {
if (templates[i].endsWith(".template")) try {
//System.out.println("TEMPLATE " + templates[i].substring(0, templates[i].length() - 9) + ": " + new String(buf, 0, c));
result.put(templates[i].substring(0, templates[i].length() - 9),
new String(serverFileUtils.read(new File(path, templates[i])), "UTF-8"));
} catch (Exception e) {}
}
return result;
}
/**
* TODO: handle accept-charset http header
* TODO: what about content-encoding, transfer-encoding here?
*/
protected void sendMessage(Properties conProp, httpHeader requestHeader, OutputStream out, int statusCode, String statusText, String contentType, byte[] MessageBody) throws IOException {
// write out the response header
respondHeader(conProp, out, statusCode, statusText, (MessageBody==null)?null:contentType, (MessageBody==null)?-1:MessageBody.length, null, null);
// write the message body
if (MessageBody != null) out.write(MessageBody);
out.flush();
}
/**
* TODO: handle accept-charset http header
*/
protected void sendMessage(Properties conProp, httpHeader requestHeader, OutputStream out, int statusCode, String statusText, Message soapMessage) throws IOException, SOAPException {
httpChunkedOutputStream chunkedOut = null;
GZIPOutputStream gzipOut = null;
OutputStream bodyOut = out;
// getting the content type of the response
String contentType = soapMessage.getContentType(soapMessage.getMessageContext().getSOAPConstants());
// getting the content length
String transferEncoding = null;
String contentEncoding = null;
long contentLength = -1;
if (httpHeader.supportChunkedEncoding(conProp)) {
// we use chunked transfer encoding
transferEncoding = "chunked";
} else {
contentLength = soapMessage.getContentLength();
}
if (requestHeader.acceptGzip()) {
// send the response gzip encoded
contentEncoding = "gzip";
// we don't know the content length of the compressed body
contentLength = -1;
// if chunked transfer encoding is not used we need to close the connection
if (!transferEncoding.equals("chunked")) {
conProp.setProperty(httpHeader.CONNECTION_PROP_PERSISTENT,"close");
}
}
// sending the soap header
respondHeader(conProp, out, statusCode, statusText, contentType, contentLength, contentEncoding, transferEncoding);
if (transferEncoding != null) bodyOut = chunkedOut = new httpChunkedOutputStream(bodyOut);
if (contentEncoding != null) bodyOut = gzipOut = new GZIPOutputStream(bodyOut);
// sending the body
soapMessage.writeTo(bodyOut);
bodyOut.flush();
if (gzipOut != null) {
gzipOut.flush();
gzipOut.finish();
}
if (chunkedOut != null) {
chunkedOut.finish();
}
}
protected void respondHeader(
Properties conProp,
OutputStream respond,
int httpStatusCode,
String httpStatusText,
String conttype,
long contlength,
String contentEncoding,
String transferEncoding
) throws IOException {
httpHeader outgoingHeader = new httpHeader();
outgoingHeader.put(httpHeader.SERVER, SOAP_HANDLER_VERSION);
if (conttype != null) outgoingHeader.put(httpHeader.CONTENT_TYPE,conttype);
if (contlength != -1) outgoingHeader.put(httpHeader.CONTENT_LENGTH, Long.toString(contlength));
if (contentEncoding != null) outgoingHeader.put(httpHeader.CONTENT_ENCODING, contentEncoding);
if (transferEncoding != null) outgoingHeader.put(httpHeader.TRANSFER_ENCODING, transferEncoding);
// getting the http version of the soap client
String httpVer = conProp.getProperty(httpHeader.CONNECTION_PROP_HTTP_VER);
// sending http headers
httpd.sendRespondHeader(conProp,respond,httpVer,httpStatusCode,httpStatusText,outgoingHeader);
}
}