*) Redesign of YaCy SOAP handler

- should be more fail-safe now
   - better handling of compressed request bodies
   - better handling of persistent connections
   - better handling of AxisFaults

git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@2659 6c8d7289-2bf4-0310-a012-ef5d649a1542
pull/1/head
theli 19 years ago
parent 009a33170b
commit 241b881560

@ -0,0 +1,84 @@
//SoapException.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 org.apache.axis.Message;
import de.anomic.http.httpHeader;
public class SoapException extends Exception {
private int statusCode = 500;
private String statusText = (String) httpHeader.http1_1.get(Integer.toString(this.statusCode));
private Object errorMsg = this.statusText;
public SoapException(int httpStatusCode, String httpStatusText, String errorMsg) {
super(httpStatusCode + " " + httpStatusText);
this.statusCode = httpStatusCode;
this.statusText = httpStatusText;
this.errorMsg = errorMsg;
}
public SoapException(int httpStatusCode, String httpStatusText, Message errorMsg) {
super(httpStatusCode + " " + httpStatusText);
this.statusCode = httpStatusCode;
this.statusText = httpStatusText;
this.errorMsg = errorMsg;
}
public int getStatusCode() {
return this.statusCode;
}
public String getStatusText() {
return this.statusText;
}
public Object getErrorMsg() {
return this.errorMsg;
}
}

@ -1,18 +1,22 @@
package de.anomic.soap; package de.anomic.soap;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PushbackInputStream; import java.io.PushbackInputStream;
import java.util.Date; import java.io.UnsupportedEncodingException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Properties; import java.util.Properties;
import java.util.zip.GZIPInputStream;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.SOAPException;
import org.apache.axis.AxisFault;
import org.apache.axis.Constants; import org.apache.axis.Constants;
import org.apache.axis.EngineConfiguration; import org.apache.axis.EngineConfiguration;
import org.apache.axis.Message; import org.apache.axis.Message;
@ -20,11 +24,15 @@ import org.apache.axis.MessageContext;
import org.apache.axis.WSDDEngineConfiguration; import org.apache.axis.WSDDEngineConfiguration;
import org.apache.axis.deployment.wsdd.WSDDDeployment; import org.apache.axis.deployment.wsdd.WSDDDeployment;
import org.apache.axis.deployment.wsdd.WSDDDocument; import org.apache.axis.deployment.wsdd.WSDDDocument;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.axis.message.SOAPFault;
import org.apache.axis.server.AxisServer; import org.apache.axis.server.AxisServer;
import org.apache.axis.utils.XMLUtils; import org.apache.axis.utils.XMLUtils;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import de.anomic.http.httpChunkedInputStream;
import de.anomic.http.httpContentLengthInputStream;
import de.anomic.http.httpHeader; import de.anomic.http.httpHeader;
import de.anomic.http.httpc; import de.anomic.http.httpc;
import de.anomic.http.httpdAbstractHandler; import de.anomic.http.httpdAbstractHandler;
@ -33,6 +41,7 @@ import de.anomic.server.serverClassLoader;
import de.anomic.server.serverCore; import de.anomic.server.serverCore;
import de.anomic.server.serverFileUtils; import de.anomic.server.serverFileUtils;
import de.anomic.server.serverSwitch; import de.anomic.server.serverSwitch;
import de.anomic.server.logging.serverLog;
/** /**
* Class to accept SOAP Requests and invoke the desired soapService. * Class to accept SOAP Requests and invoke the desired soapService.
@ -81,10 +90,12 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
+ "xmlns=\"http://xml.apache.org/axis/wsdd/\" " + "xmlns=\"http://xml.apache.org/axis/wsdd/\" "
+ "xmlns:java=\"http://xml.apache.org/axis/wsdd/providers/java\" >" + "xmlns:java=\"http://xml.apache.org/axis/wsdd/providers/java\" >"
+ "<service name=\"index\" provider=\"java:RPC\" >" + "<service name=\"index\" provider=\"java:RPC\" >"
+ "<parameter name=\"typeMappingVersion\" value=\"1.1\"/>"
+ "<parameter name=\"scope\" value=\"Request\"/>"
+ "<parameter name=\"className\" value=\"de.anomic.soap.httpdSoapService\" />" + "<parameter name=\"className\" value=\"de.anomic.soap.httpdSoapService\" />"
+ "<parameter name=\"allowedMethods\" value=\"*\" />" + "<parameter name=\"allowedMethods\" value=\"*\" />"
+ "</service>" + "</service>"
+ "</deployment>"; + "</deployment>";
/* =============================================================== /* ===============================================================
* Constants needed to set the SOAP message context * Constants needed to set the SOAP message context
@ -125,8 +136,7 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
* Creating and configuring an apache Axis server. * Creating and configuring an apache Axis server.
* This is only needed once. * This is only needed once.
*/ */
static static {
{
// create an Axis server // create an Axis server
engine = new AxisServer(); engine = new AxisServer();
@ -141,11 +151,11 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
* Constructor of this class * Constructor of this class
* @param switchboard * @param switchboard
*/ */
public httpdSoapHandler(serverSwitch switchboard) public httpdSoapHandler(serverSwitch switchboard) {
{
super(); super();
this.switchboard = switchboard; this.switchboard = switchboard;
this.theLogger = new serverLog("SOAP");
// create a htRootPath: system pages // create a htRootPath: system pages
if (this.htRootPath == null) { if (this.htRootPath == null) {
@ -164,7 +174,94 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
if (this.templates == null) this.templates = loadTemplates(this.htTemplatePath); if (this.templates == null) this.templates = loadTemplates(this.htTemplatePath);
} }
private byte[] readRequestBody(httpHeader requestHeader, PushbackInputStream body) throws SoapException {
try {
// getting an input stream to handle transfer encoding and content encoding properly
InputStream soapInput = getBodyInputStream(requestHeader, body);
// read the content
return serverFileUtils.read(soapInput);
} catch (IOException e) {
throw new SoapException(500,"Read error",e.getMessage());
}
}
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")) {
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) {
input = new httpContentLengthInputStream(body,contentLength);
} else {
input = body;
}
/* ===========================================================================
* Handle CONTENT ENCODING
* =========================================================================== */
try {
if (contentEncoding != null && !contentEncoding.equals("identity")) {
if (contentEncoding.equalsIgnoreCase("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.getMessage());
}
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 header, OutputStream clientOut) throws IOException {
sendMessage(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(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. * 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 * Therefore we always return the wsdl file for a get request
@ -177,78 +274,54 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
* *
* @see de.anomic.http.httpdHandler#doGet(java.util.Properties, de.anomic.http.httpHeader, java.io.OutputStream) * @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 public void doGet(Properties conProp, httpHeader requestHeader, OutputStream response) throws IOException {
{ String path = conProp.getProperty(httpHeader.CONNECTION_PROP_PATH);
String path = conProp.getProperty("PATH"); try {
try MessageContext msgContext = this.generateMessageContext(path, requestHeader, conProp);
{
MessageContext msgContext = this.generateMessageContext(path, requestHeader);
engine.generateWSDL(msgContext); Document doc = null;
Document doc = (Document) msgContext.getProperty("WSDL"); try {
engine.generateWSDL(msgContext);
doc = (Document) msgContext.getProperty("WSDL");
} catch (AxisFault ex) {
Message errorMsg = faultToMessage(null, msgContext, ex);
throw new SoapException(500,"Unable to generate WSDL",errorMsg);
}
if (doc != null) if (doc != null) {
{
// Converting the the wsdl document into a byte-array // Converting the the wsdl document into a byte-array
String responseDoc = XMLUtils.DocumentToString(doc); String responseDoc = XMLUtils.DocumentToString(doc);
byte[] result = responseDoc.getBytes(); byte[] result = responseDoc.getBytes("UTF-8");
/* // send back the result
* Setting the response header sendMessage(response, 200, "OK", "text/xml; charset=utf-8", result);
* - Status: 200 OK
* - Content Type: text/xml
* - Encoding: UTF8
* - Date: current Date
*/
respondHeader(response, 200, "text/xml; charset=utf-8", result.length, new Date(), null, null);
// writing out the data
Thread.currentThread().join(200);
serverFileUtils.write(result, response);
response.flush();
if (!(requestHeader.get("Connection", "close").equals("keep-alive"))) { if (!(requestHeader.get("Connection", "close").equals("keep-alive"))) {
// wait a little time until everything closes so that clients can read from the streams/sockets // wait a little time until everything closes so that clients can read from the streams/sockets
try {Thread.currentThread().join(1000);} catch (InterruptedException e) {} try {Thread.currentThread().join(200);} catch (InterruptedException e) {/* ignore this */}
} }
} } else {
// if we where unable to generate the wsdl file ....
// if we where unable to generate the wsdl file ....
else
{
String errorMsg = "Internal Server Error: Unable to generate the WSDL file."; String errorMsg = "Internal Server Error: Unable to generate the WSDL file.";
respondHeader(response, 500, "text/plain", errorMsg.length(), httpc.nowDate(), null, null); sendMessage(response, 500, "Internal Error", "text/plain",errorMsg.getBytes("UTF-8"));
response.write(errorMsg.getBytes());
response.flush();
} }
return; return;
} } catch (SoapException e) {
catch (Exception e) try {
{ sendSoapException(response, e);
System.out.println("ERROR: Exception with query: " + path + "; '" + e.toString() + ":" + e.getMessage() + "'\r\n"); } catch (Exception ex) {
this.theLogger.logSevere("Unexpected Exception while sending error message",e);
} finally {
conProp.setProperty(httpHeader.CONNECTION_PROP_PERSISTENT,"close");
}
} catch (Exception e) {
conProp.setProperty(httpHeader.CONNECTION_PROP_PERSISTENT,"close");
this.theLogger.logSevere("Unexpected Exception with query: " + path,e);
} }
} }
/**
* 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 header, OutputStream response) throws IOException
{
// the http HEAD method is not allowed for this SOAP API
String errorMsg = "Method Not Allowed";
respondHeader(response, 405, "text/plain", errorMsg.length(), httpc.nowDate(), null, null);
response.write(errorMsg.getBytes());
response.flush();
}
/** /**
* HTTP Post method. Needed to call a soap service on this server from a soap client * HTTP Post method. Needed to call a soap service on this server from a soap client
* @param conProp the connection properties * @param conProp the connection properties
@ -260,82 +333,111 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
* *
* @see de.anomic.http.httpdHandler#doPost(java.util.Properties, de.anomic.http.httpHeader, java.io.OutputStream, java.io.PushbackInputStream) * @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) throws IOException public void doPost(Properties conProp, httpHeader requestHeader, OutputStream response, PushbackInputStream body) throws IOException {
{ String path = conProp.getProperty(httpHeader.CONNECTION_PROP_PATH);
String path = conProp.getProperty("PATH"); try {
try /* ========================================================================
{ * GENERATE REQUEST MESSAGE
/* * ======================================================================== */
* Converting the request body into a bytehstream needed by the apache // read the request message
* axis engine byte[] buffer = readRequestBody(requestHeader, body);
*/
int contentLength = requestHeader.containsKey("CONTENT-LENGTH")?
Integer.parseInt((String) requestHeader.get("CONTENT-LENGTH")):
0;
byte[] buffer = new byte[contentLength];
body.read(buffer);
InputStream soapInputStream = new ByteArrayInputStream(buffer);
/* // generating the SOAP message context that will be passed over to the invoked service
* generating the SOAP message context that will be passed over to the invoked MessageContext msgContext = this.generateMessageContext(path, requestHeader, conProp);
* service
*/
MessageContext msgContext = this.generateMessageContext(path, requestHeader);
/* // Generating a SOAP Request Message Object
* Generating a SOAP Request Message Object from the XML document Message requestMsg = new Message(
* and store it into the message context buffer,
*/ false,
Message requestMsg = new Message(soapInputStream, false, "text/xml;charset=\"utf-8\"", ""); requestHeader.mime(),
(String)requestHeader.get(httpHeader.CONTENT_LOCATION)
);
msgContext.setRequestMessage(requestMsg); msgContext.setRequestMessage(requestMsg);
/* ========================================================================
* SERVICE INVOCATION
* ======================================================================== */
Message responseMsg = this.invokeService(msgContext);
if (responseMsg != null) {
sendMessage(response, 200, "OK", responseMsg);
} else {
sendMessage(response, 202, "Accepted", "text/plain", null);
}
return;
} catch (SoapException e) {
try {
sendSoapException(response, e);
} catch (Exception ex) {
this.theLogger.logSevere("Unexpected Exception while sending error message",e);
} finally {
conProp.setProperty(httpHeader.CONNECTION_PROP_PERSISTENT,"close");
}
} catch (Exception e) {
conProp.setProperty(httpHeader.CONNECTION_PROP_PERSISTENT,"close");
this.theLogger.logSevere("Unexpected Exception",e);
}
}
protected Message invokeService(MessageContext msgContext) throws SoapException {
int invocationStatusCode = 200;
String invocationStatusText = "OK";
try {
// invoke the service // invoke the service
engine.invoke(msgContext); engine.invoke(msgContext);
// Retrieve the response from Axis // Retrieve the response from Axis
Message responseMsg = msgContext.getResponseMessage(); return msgContext.getResponseMessage();
} catch (Exception ex) {
if (responseMsg != null) Message errorMsg;
{ AxisFault soapFault;
respondHeader(response, 200, "text/xml; charset=utf-8", responseMsg.getContentLength(), new Date(), null, null); if (ex instanceof AxisFault) {
Thread.currentThread().join(200); soapFault = (AxisFault) ex;
responseMsg.writeTo(response);
response.flush(); QName faultCode = soapFault.getFaultCode();
} if (Constants.FAULT_SOAP12_SENDER.equals(faultCode)) {
else invocationStatusCode = 400;
{ invocationStatusText = "Bad request";
String errorMsg = "Internal Server Error: Unable to invoke the requested service."; } else if ("Server.Unauthorized".equals(faultCode.getLocalPart())) {
respondHeader(response, 500, "text/plain", errorMsg.length(), httpc.nowDate(), null, null); invocationStatusCode = 401;
response.write(errorMsg.getBytes()); invocationStatusText = "Unauthorized";
response.flush(); } else {
invocationStatusCode = 500;
invocationStatusText = "Internal server error";
}
} else {
invocationStatusCode = 500;
invocationStatusText = "Internal server error";
soapFault = AxisFault.makeFault(ex);
} }
return; // There may be headers we want to preserve in the
} // response message - so if it's there, just add the
catch (Exception e) // FaultElement to it. Otherwise, make a new one.
{ errorMsg = msgContext.getResponseMessage();
System.out.println("ERROR: Exception with query: " + path + "; '" + e.toString() + ":" + e.getMessage() + "'\r\n"); errorMsg = faultToMessage(errorMsg, msgContext, soapFault);
throw new SoapException(invocationStatusCode,invocationStatusText,errorMsg);
} }
} }
/** protected Message faultToMessage(Message errorMsg, MessageContext msgContext, AxisFault soapFault) {
* HTTP Connect Method. Not needed for SOAP Message theErrorMsg = errorMsg;
* @param conProp if (theErrorMsg == null) {
* @param requestHeader theErrorMsg = new Message(soapFault);
* @param clientIn theErrorMsg.setMessageContext(msgContext);
* @param clientOut } else {
* @throws IOException try {
* SOAPEnvelope env = theErrorMsg.getSOAPEnvelope();
* @see de.anomic.http.httpdHandler#doConnect(java.util.Properties, de.anomic.http.httpHeader, java.io.InputStream, java.io.OutputStream) env.clearBody();
*/ env.addBodyElement(new SOAPFault(soapFault));
public void doConnect(Properties conProp, httpHeader requestHeader, InputStream clientIn, OutputStream clientOut) throws IOException } catch (AxisFault fault) {
{ // Should never reach here!
// the CONNECT method is not allowed for this SOAP API }
String errorMsg = "Method Not Allowed"; }
respondHeader(clientOut, 405, "text/plain", errorMsg.length(), httpc.nowDate(), null, null); return theErrorMsg;
clientOut.write(errorMsg.getBytes());
clientOut.flush();
} }
/** /**
@ -352,14 +454,11 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
{ {
// convert WSDD file string into bytestream for furhter processing // convert WSDD file string into bytestream for furhter processing
InputStream deploymentStream = null; InputStream deploymentStream = null;
if (deploymentString != null) if (deploymentString != null) {
{ deploymentStream = new ByteArrayInputStream(deploymentString.getBytes());
deploymentStream = new ByteArrayInputStream(deploymentString.getBytes());
Document root = null; Document root = null;
try try {
{
// build XML document from stream // build XML document from stream
root = XMLUtils.newDocument(deploymentStream); root = XMLUtils.newDocument(deploymentStream);
@ -369,8 +468,7 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
// get the configuration of this axis engine // get the configuration of this axis engine
EngineConfiguration config = theAxisServer.getConfig(); EngineConfiguration config = theAxisServer.getConfig();
if (config instanceof WSDDEngineConfiguration) if (config instanceof WSDDEngineConfiguration) {
{
// get the current configuration of the Axis engine // get the current configuration of the Axis engine
WSDDDeployment deploymentWSDD = WSDDDeployment deploymentWSDD =
((WSDDEngineConfiguration) config).getDeployment(); ((WSDDEngineConfiguration) config).getDeployment();
@ -383,25 +481,17 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
// an existing service with the same name gets deleted // an existing service with the same name gets deleted
wsddDoc.deploy(deploymentWSDD); wsddDoc.deploy(deploymentWSDD);
} }
} } catch (ParserConfigurationException e) {
catch (ParserConfigurationException e)
{
System.err.println("Could not deploy service."); System.err.println("Could not deploy service.");
return false; return false;
} } catch (SAXException e) {
catch (SAXException e)
{
System.err.println("Could not deploy service."); System.err.println("Could not deploy service.");
return false; return false;
} } catch (IOException e) {
catch (IOException e)
{
System.err.println("Could not deploy service."); System.err.println("Could not deploy service.");
return false; return false;
} }
} } else {
else
{
System.err.println("Service deployment string is NULL! SOAP Service not deployed."); System.err.println("Service deployment string is NULL! SOAP Service not deployed.");
return false; return false;
} }
@ -415,38 +505,39 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
* *
* @param path the path of the request * @param path the path of the request
* @param requestHeader the http headers of the request * @param requestHeader the http headers of the request
* * @param conProps TODO
* @return the generated {@link MessageContext} * @return the generated {@link MessageContext}
* @throws SoapException
* *
* @throws Exception if the {@link MessageContext} could not be generated successfully. * @throws Exception if the {@link MessageContext} could not be generated successfully.
*/ */
private MessageContext generateMessageContext(String path, httpHeader requestHeader) private MessageContext generateMessageContext(String path, httpHeader requestHeader, Properties conProps) throws SoapException {
throws Exception try {
{ // getting the requestes service name
try String serviceName = path.substring("/soap/".length());
{
// create and initialize a message context // create and initialize a message context
MessageContext msgContext = new MessageContext(httpdSoapHandler.engine); MessageContext msgContext = new MessageContext(httpdSoapHandler.engine);
msgContext.setTransportName("SimpleHTTP"); msgContext.setTransportName("YaCy-SOAP");
msgContext.setProperty(org.apache.axis.Constants.MC_REALPATH, path.toString()); 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")))) +
msgContext.setProperty(Constants.MC_RELATIVE_PATH, path.toString()); "/soap/" + serviceName);
msgContext.setProperty(Constants.MC_JWS_CLASSDIR, "jwsClasses");
msgContext.setProperty(Constants.MC_HOME_DIR, ".");
msgContext.setProperty(MessageContext.TRANS_URL, "http://" + requestHeader.get("Host") + ((((String)requestHeader.get("Host")).indexOf(":") > -1)?"":Integer.toString(serverCore.getPortNr(this.switchboard.getConfig("port","8080")))) + "/soap/index");
// the used http verson
String version = conProps.getProperty(httpHeader.CONNECTION_PROP_HTTP_VER);
msgContext.setProperty(MessageContext.HTTP_TRANSPORT_VERSION,version);
// YaCy specific objects
msgContext.setProperty(MESSAGE_CONTEXT_HTTP_ROOT_PATH ,this.htRootPath.toString()); msgContext.setProperty(MESSAGE_CONTEXT_HTTP_ROOT_PATH ,this.htRootPath.toString());
msgContext.setProperty(MESSAGE_CONTEXT_SERVER_SWITCH,this.switchboard); msgContext.setProperty(MESSAGE_CONTEXT_SERVER_SWITCH,this.switchboard);
msgContext.setProperty(MESSAGE_CONTEXT_HTTP_HEADER ,requestHeader); msgContext.setProperty(MESSAGE_CONTEXT_HTTP_HEADER ,requestHeader);
msgContext.setProperty(MESSAGE_CONTEXT_SERVER_CLASSLOADER ,this.provider); msgContext.setProperty(MESSAGE_CONTEXT_SERVER_CLASSLOADER ,this.provider);
msgContext.setProperty(MESSAGE_CONTEXT_TEMPLATES ,this.templates); msgContext.setProperty(MESSAGE_CONTEXT_TEMPLATES ,this.templates);
msgContext.setTargetService(path.substring(6)); msgContext.setTargetService(serviceName);
return msgContext; return msgContext;
} } catch (AxisFault e) {
catch (Exception e) throw new SoapException(500,"Unable to set the target service",e.getMessage());
{
throw new Exception ("Unable to generate the message context. ",e);
} }
} }
@ -475,6 +566,56 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
return result; return result;
} }
protected void sendSoapException(OutputStream out, SoapException e) throws UnsupportedEncodingException, IOException, SOAPException {
Object errorMsg = e.getErrorMsg();
String contentType = null;
// getting the error message body and content length
ByteArrayOutputStream bout = new ByteArrayOutputStream();
if (errorMsg instanceof String) {
bout.write(((String)errorMsg).getBytes("UTF-8"));
contentType = "text/plain; charset=UTF-8";
} else {
Message soapErrorMsg = (Message)errorMsg;
soapErrorMsg.writeTo(bout);
contentType = soapErrorMsg.getContentType(soapErrorMsg.getMessageContext().getSOAPConstants());
}
// send out the message
sendMessage(out, e.getStatusCode(), e.getStatusText(), contentType, bout.toByteArray());
}
protected void sendMessage(OutputStream out, int statusCode, String statusText, String contentType, byte[] MessageBody) throws IOException {
// write out the response header
respondHeader(out, statusCode, statusText, (MessageBody==null)?null:contentType, (MessageBody==null)?-1:MessageBody.length);
// write the message body
if (MessageBody != null) out.write(MessageBody);
out.flush();
}
protected void sendMessage(OutputStream out, int statusCode, String statusText, Message soapMessage) throws IOException, SoapException {
// getting the content body
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
soapMessage.writeTo(bout);
} catch (SOAPException e) {
throw new SoapException(500,"Unable to externalize SOAP message",e.getMessage());
}
// getting the content type
String contentType = null;
try {
contentType = soapMessage.getContentType(soapMessage.getMessageContext().getSOAPConstants());
} catch (AxisFault e) {
throw new SoapException(500,"Unable to get content-type for SOAP message",e.getMessage());
}
// sending the message
sendMessage(out, statusCode, statusText, contentType, bout.toByteArray());
}
/** /**
* This method was copied from {@link httpdFileHandler}. Maybe it would be a good idea * This method was copied from {@link httpdFileHandler}. Maybe it would be a good idea
* to move this function up into {@link httpdAbstractHandler} * to move this function up into {@link httpdAbstractHandler}
@ -483,25 +624,15 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http
* @param retcode the http code * @param retcode the http code
* @param conttype the content type and encoding * @param conttype the content type and encoding
* @param contlength the content length * @param contlength the content length
* @param moddate the modification date of the content
* @param expires the date of expiry of the content
* @param cookie cookies to be send
*
* @throws IOException * @throws IOException
*/ */
protected void respondHeader(OutputStream out, int retcode, String conttype, long contlength, Date moddate, Date expires, String cookie) throws IOException protected void respondHeader(OutputStream out, int retcode, String returnStatus, String conttype, long contlength) throws IOException {
{
try { try {
out.write(("HTTP/1.1 " + retcode + " OK\r\n").getBytes()); out.write(("HTTP/1.1 " + retcode + " " + returnStatus + "\r\n").getBytes());
out.write(("Server: AnomicHTTPD (www.anomic.de)\r\n").getBytes()); out.write(("Server: AnomicHTTPD (www.anomic.de)\r\n").getBytes());
out.write(("Date: " + httpc.dateString(httpc.nowDate()) + "\r\n").getBytes()); out.write(("Date: " + httpc.dateString(httpc.nowDate()) + "\r\n").getBytes());
if (expires != null) out.write(("Expires: " + httpc.dateString(expires) + "\r\n").getBytes()); if (conttype != null) out.write((httpHeader.CONTENT_TYPE + ": " + conttype + "\r\n").getBytes());
out.write(("Content-type: " + conttype /* "image/gif", "text/html" */ + "\r\n").getBytes()); if (contlength != -1) out.write((httpHeader.CONTENT_LENGTH + ": " + contlength +"\r\n").getBytes());
out.write(("Last-modified: " + httpc.dateString(moddate) + "\r\n").getBytes());
out.write(("Content-length: " + contlength +"\r\n").getBytes());
out.write(("Pragma: no-cache\r\n").getBytes());
// out.write(("Accept-ranges: bytes\r\n").getBytes());
if (cookie != null) out.write(("Set-Cookie: " + cookie + "\r\n").getBytes());
out.write(("\r\n").getBytes()); out.write(("\r\n").getBytes());
out.flush(); out.flush();
} catch (Exception e) { } catch (Exception e) {

@ -1,3 +1,48 @@
//httpdSoapService.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; package de.anomic.soap;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -275,7 +320,7 @@ public class httpdSoapService
String authString = authElement.getValue(); String authString = authElement.getValue();
String adminAccountBase64MD5 = this.switchboard.getConfig("adminAccountBase64MD5",""); String adminAccountBase64MD5 = this.switchboard.getConfig("adminAccountBase64MD5","");
if (adminAccountBase64MD5.length() == 0) { if (authString.length() == 0) {
throw new AxisFault("log-in required"); throw new AxisFault("log-in required");
} else if (!(adminAccountBase64MD5.equals(authString))) { } else if (!(adminAccountBase64MD5.equals(authString))) {
throw new AxisFault("log-in required"); throw new AxisFault("log-in required");

Loading…
Cancel
Save