SimpleAxisWorkerpublic class SimpleAxisWorker extends Object implements Runnable
Fields Summary |
---|
protected static Log | log | private SimpleAxisServer | server | private Socket | socket | private static String | transportName | private static byte[] | OK | private static byte[] | NOCONTENT | private static byte[] | UNAUTH | private static byte[] | SENDER | private static byte[] | ISE | private static byte[] | HTTP | private static byte[] | XML_MIME_STUFF | private static byte[] | HTML_MIME_STUFF | private static byte[] | SEPARATOR | private static final byte[] | toLower | private static final int | BUFSIZ | private static final byte[] | lenHeader | private static final int | lenLen | private static final byte[] | typeHeader | private static final int | typeLen | private static final byte[] | locationHeader | private static final int | locationLen | private static final byte[] | actionHeader | private static final int | actionLen | private static final byte[] | cookieHeader | private static final int | cookieLen | private static final byte[] | cookie2Header | private static final int | cookie2Len | private static final byte[] | authHeader | private static final int | authLen | private static final byte[] | getHeader | private static final byte[] | postHeader | private static final byte[] | headerEnder | private static final byte[] | basicAuth |
Constructors Summary |
---|
public SimpleAxisWorker(SimpleAxisServer server, Socket socket)
this.server = server;
this.socket = socket;
|
Methods Summary |
---|
public void | execute()The main workhorse method.
byte buf[] = new byte[BUFSIZ];
// create an Axis server
AxisServer engine = server.getAxisServer();
// create and initialize a message context
MessageContext msgContext = new MessageContext(engine);
Message requestMsg = null;
// Reusuable, buffered, content length controlled, InputStream
NonBlockingBufferedInputStream is =
new NonBlockingBufferedInputStream();
// buffers for the headers we care about
StringBuffer soapAction = new StringBuffer();
StringBuffer httpRequest = new StringBuffer();
StringBuffer fileName = new StringBuffer();
StringBuffer cookie = new StringBuffer();
StringBuffer cookie2 = new StringBuffer();
StringBuffer authInfo = new StringBuffer();
StringBuffer contentType = new StringBuffer();
StringBuffer contentLocation = new StringBuffer();
Message responseMsg = null;
// prepare request (do as much as possible while waiting for the
// next connection). Note the next two statements are commented
// out. Uncomment them if you experience any problems with not
// resetting state between requests:
// msgContext = new MessageContext();
// requestMsg = new Message("", "String");
//msgContext.setProperty("transport", "HTTPTransport");
msgContext.setTransportName(transportName);
responseMsg = null;
try {
// assume the best
byte[] status = OK;
// assume we're not getting WSDL
boolean doWsdl = false;
// cookie for this session, if any
String cooky = null;
String methodName = null;
try {
// wipe cookies if we're doing sessions
if (server.isSessionUsed()) {
cookie.delete(0, cookie.length());
cookie2.delete(0, cookie2.length());
}
authInfo.delete(0, authInfo.length());
// read headers
is.setInputStream(socket.getInputStream());
// parse all headers into hashtable
MimeHeaders requestHeaders = new MimeHeaders();
int contentLength = parseHeaders(is, buf, contentType,
contentLocation, soapAction,
httpRequest, fileName,
cookie, cookie2, authInfo, requestHeaders);
is.setContentLength(contentLength);
int paramIdx = fileName.toString().indexOf('?");
if (paramIdx != -1) {
// Got params
String params = fileName.substring(paramIdx + 1);
fileName.setLength(paramIdx);
log.debug(Messages.getMessage("filename00",
fileName.toString()));
log.debug(Messages.getMessage("params00",
params));
if ("wsdl".equalsIgnoreCase(params))
doWsdl = true;
if (params.startsWith("method=")) {
methodName = params.substring(7);
}
}
// Real and relative paths are the same for the
// SimpleAxisServer
msgContext.setProperty(Constants.MC_REALPATH,
fileName.toString());
msgContext.setProperty(Constants.MC_RELATIVE_PATH,
fileName.toString());
msgContext.setProperty(Constants.MC_JWS_CLASSDIR,
"jwsClasses");
msgContext.setProperty(Constants.MC_HOME_DIR, ".");
// !!! Fix string concatenation
String url = "http://" + getLocalHost() + ":" +
server.getServerSocket().getLocalPort() + "/" +
fileName.toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
String filePart = fileName.toString();
if (filePart.startsWith("axis/services/")) {
String servicePart = filePart.substring(14);
int separator = servicePart.indexOf('/");
if (separator > -1) {
msgContext.setProperty("objectID",
servicePart.substring(separator + 1));
servicePart = servicePart.substring(0, separator);
}
msgContext.setTargetService(servicePart);
}
if (authInfo.length() > 0) {
// Process authentication info
//authInfo = new StringBuffer("dXNlcjE6cGFzczE=");
byte[] decoded = Base64.decode(authInfo.toString());
StringBuffer userBuf = new StringBuffer();
StringBuffer pwBuf = new StringBuffer();
StringBuffer authBuf = userBuf;
for (int i = 0; i < decoded.length; i++) {
if ((char) (decoded[i] & 0x7f) == ':") {
authBuf = pwBuf;
continue;
}
authBuf.append((char) (decoded[i] & 0x7f));
}
if (log.isDebugEnabled()) {
log.debug(Messages.getMessage("user00",
userBuf.toString()));
}
msgContext.setUsername(userBuf.toString());
msgContext.setPassword(pwBuf.toString());
}
// if get, then return simpleton document as response
if (httpRequest.toString().equals("GET")) {
OutputStream out = socket.getOutputStream();
out.write(HTTP);
if(fileName.length()==0) {
out.write("301 Redirect\nLocation: /axis/\n\n".getBytes());
out.flush();
return;
}
out.write(status);
if (methodName != null) {
String body =
"<" + methodName + ">" +
// args +
"</" + methodName + ">";
String msgtxt =
"<SOAP-ENV:Envelope" +
" xmlns:SOAP-ENV=\"" + Constants.URI_SOAP12_ENV + "\">" +
"<SOAP-ENV:Body>" + body + "</SOAP-ENV:Body>" +
"</SOAP-ENV:Envelope>";
ByteArrayInputStream istream =
new ByteArrayInputStream(msgtxt.getBytes());
requestMsg = new Message(istream);
} else if (doWsdl) {
engine.generateWSDL(msgContext);
Document doc = (Document) msgContext.getProperty("WSDL");
if (doc != null) {
XMLUtils.normalize(doc.getDocumentElement());
String response = XMLUtils.PrettyDocumentToString(doc);
byte[] respBytes = response.getBytes();
out.write(XML_MIME_STUFF);
putInt(buf, out, respBytes.length);
out.write(SEPARATOR);
out.write(respBytes);
out.flush();
return;
}
} else {
StringBuffer sb = new StringBuffer();
sb.append("<h2>And now... Some Services</h2>\n");
Iterator i = engine.getConfig().getDeployedServices();
sb.append("<ul>\n");
while (i.hasNext()) {
ServiceDesc sd = (ServiceDesc)i.next();
sb.append("<li>\n");
sb.append(sd.getName());
sb.append(" <a href=\"services/");
sb.append(sd.getName());
sb.append("?wsdl\"><i>(wsdl)</i></a></li>\n");
ArrayList operations = sd.getOperations();
if (!operations.isEmpty()) {
sb.append("<ul>\n");
for (Iterator it = operations.iterator(); it.hasNext();) {
OperationDesc desc = (OperationDesc) it.next();
sb.append("<li>" + desc.getName());
}
sb.append("</ul>\n");
}
}
sb.append("</ul>\n");
byte [] bytes = sb.toString().getBytes();
out.write(HTML_MIME_STUFF);
putInt(buf, out, bytes.length);
out.write(SEPARATOR);
out.write(bytes);
out.flush();
return;
}
} else {
// this may be "" if either SOAPAction: "" or if no SOAPAction at all.
// for now, do not complain if no SOAPAction at all
String soapActionString = soapAction.toString();
if (soapActionString != null) {
msgContext.setUseSOAPAction(true);
msgContext.setSOAPActionURI(soapActionString);
}
requestMsg = new Message(is,
false,
contentType.toString(),
contentLocation.toString()
);
}
// Transfer HTTP headers to MIME headers for request message.
MimeHeaders requestMimeHeaders = requestMsg.getMimeHeaders();
for (Iterator i = requestHeaders.getAllHeaders(); i.hasNext(); ) {
MimeHeader requestHeader = (MimeHeader) i.next();
requestMimeHeaders.addHeader(requestHeader.getName(), requestHeader.getValue());
}
msgContext.setRequestMessage(requestMsg);
// put character encoding of request to message context
// in order to reuse it during the whole process.
String requestEncoding = (String) requestMsg.getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
if (requestEncoding != null) {
msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, requestEncoding);
}
// set up session, if any
if (server.isSessionUsed()) {
// did we get a cookie?
if (cookie.length() > 0) {
cooky = cookie.toString().trim();
} else if (cookie2.length() > 0) {
cooky = cookie2.toString().trim();
}
// if cooky is null, cook up a cooky
if (cooky == null) {
// fake one up!
// make it be an arbitrarily increasing number
// (no this is not thread safe because ++ isn't atomic)
int i = SimpleAxisServer.sessionIndex++;
cooky = "" + i;
}
msgContext.setSession(server.createSession(cooky));
}
// invoke the Axis engine
engine.invoke(msgContext);
// Retrieve the response from Axis
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
status = NOCONTENT;
}
} catch (Exception e) {
AxisFault af;
if (e instanceof AxisFault) {
af = (AxisFault) e;
log.debug(Messages.getMessage("serverFault00"), af);
QName faultCode = af.getFaultCode();
if (Constants.FAULT_SOAP12_SENDER.equals(faultCode)) {
status = SENDER;
} else if ("Server.Unauthorized".equals(af.getFaultCode().getLocalPart())) {
status = UNAUTH; // SC_UNAUTHORIZED
} else {
status = ISE; // SC_INTERNAL_SERVER_ERROR
}
} else {
status = ISE; // SC_INTERNAL_SERVER_ERROR
af = AxisFault.makeFault(e);
}
// There may be headers we want to preserve in the
// response message - so if it's there, just add the
// FaultElement to it. Otherwise, make a new one.
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
responseMsg = new Message(af);
responseMsg.setMessageContext(msgContext);
} else {
try {
SOAPEnvelope env = responseMsg.getSOAPEnvelope();
env.clearBody();
env.addBodyElement(new SOAPFault((AxisFault) e));
} catch (AxisFault fault) {
// Should never reach here!
}
}
}
// synchronize the character encoding of request and response
String responseEncoding = (String) msgContext.getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
if (responseEncoding != null && responseMsg != null) {
responseMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, responseEncoding);
}
// Send it on its way...
OutputStream out = socket.getOutputStream();
out.write(HTTP);
out.write(status);
if (responseMsg != null) {
if (server.isSessionUsed() && null != cooky &&
0 != cooky.trim().length()) {
// write cookie headers, if any
// don't sweat efficiency *too* badly
// optimize at will
StringBuffer cookieOut = new StringBuffer();
cookieOut.append("\r\nSet-Cookie: ")
.append(cooky)
.append("\r\nSet-Cookie2: ")
.append(cooky);
// OH, THE HUMILITY! yes this is inefficient.
out.write(cookieOut.toString().getBytes());
}
//out.write(XML_MIME_STUFF);
out.write(("\r\n" + HTTPConstants.HEADER_CONTENT_TYPE + ": " + responseMsg.getContentType(msgContext.getSOAPConstants())).getBytes());
// Writing the length causes the entire message to be decoded twice.
//out.write(("\r\n" + HTTPConstants.HEADER_CONTENT_LENGTH + ": " + responseMsg.getContentLength()).getBytes());
// putInt(out, response.length);
// Transfer MIME headers to HTTP headers for response message.
for (Iterator i = responseMsg.getMimeHeaders().getAllHeaders(); i.hasNext(); ) {
MimeHeader responseHeader = (MimeHeader) i.next();
out.write('\r");
out.write('\n");
out.write(responseHeader.getName().getBytes());
out.write(headerEnder);
out.write(responseHeader.getValue().getBytes());
}
out.write(SEPARATOR);
responseMsg.writeTo(out);
}
// out.write(response);
out.flush();
} catch (Exception e) {
log.info(Messages.getMessage("exception00"), e);
} finally {
try {
if (socket != null) socket.close();
} catch (Exception e) {
}
}
if (msgContext.getProperty(MessageContext.QUIT_REQUESTED) != null) {
// why then, quit!
try {
server.stop();
} catch (Exception e) {
}
}
| public static java.lang.String | getLocalHost()One method for all host name lookups.
return NetworkUtils.getLocalHostname();
| protected void | invokeMethodFromGet(java.lang.String methodName, java.lang.String args)
| public boolean | matches(byte[] buf, byte[] target)does tolower[buf] match the target byte array, up to the target's length?
for (int i = 0; i < target.length; i++) {
if (toLower[buf[i]] != target[i]) {
return false;
}
}
return true;
| public boolean | matches(byte[] buf, int bufIdx, byte[] target)Case-insensitive match of a target byte [] to a source byte [],
starting from a particular offset into the source.
for (int i = 0; i < target.length; i++) {
if (toLower[buf[bufIdx + i]] != target[i]) {
return false;
}
}
return true;
| private int | parseHeaders(NonBlockingBufferedInputStream is, byte[] buf, java.lang.StringBuffer contentType, java.lang.StringBuffer contentLocation, java.lang.StringBuffer soapAction, java.lang.StringBuffer httpRequest, java.lang.StringBuffer fileName, java.lang.StringBuffer cookie, java.lang.StringBuffer cookie2, java.lang.StringBuffer authInfo, javax.xml.soap.MimeHeaders headers)Read all mime headers, returning the value of Content-Length and
SOAPAction.
int n;
int len = 0;
// parse first line as GET or POST
n = this.readLine(is, buf, 0, buf.length);
if (n < 0) {
// nothing!
throw new java.io.IOException(Messages.getMessage("unexpectedEOS00"));
}
// which does it begin with?
httpRequest.delete(0, httpRequest.length());
fileName.delete(0, fileName.length());
contentType.delete(0, contentType.length());
contentLocation.delete(0, contentLocation.length());
if (buf[0] == getHeader[0]) {
httpRequest.append("GET");
for (int i = 0; i < n - 5; i++) {
char c = (char) (buf[i + 5] & 0x7f);
if (c == ' ")
break;
fileName.append(c);
}
log.debug(Messages.getMessage("filename01", "SimpleAxisServer", fileName.toString()));
return 0;
} else if (buf[0] == postHeader[0]) {
httpRequest.append("POST");
for (int i = 0; i < n - 6; i++) {
char c = (char) (buf[i + 6] & 0x7f);
if (c == ' ")
break;
fileName.append(c);
}
log.debug(Messages.getMessage("filename01", "SimpleAxisServer", fileName.toString()));
} else {
throw new java.io.IOException(Messages.getMessage("badRequest00"));
}
while ((n = readLine(is, buf, 0, buf.length)) > 0) {
if ((n <= 2) && (buf[0] == '\n" || buf[0] == '\r") && (len > 0)) break;
// RobJ gutted the previous logic; it was too hard to extend for more headers.
// Now, all it does is search forwards for ": " in the buf,
// then do a length / byte compare.
// Hopefully this is still somewhat efficient (Sam is watching!).
// First, search forwards for ": "
int endHeaderIndex = 0;
while (endHeaderIndex < n && toLower[buf[endHeaderIndex]] != headerEnder[0]) {
endHeaderIndex++;
}
endHeaderIndex += 2;
// endHeaderIndex now points _just past_ the ": ", and is
// comparable to the various lenLen, actionLen, etc. values
// convenience; i gets pre-incremented, so initialize it to one less
int i = endHeaderIndex - 1;
// which header did we find?
if (endHeaderIndex == lenLen && matches(buf, lenHeader)) {
// parse content length
while ((++i < n) && (buf[i] >= '0") && (buf[i] <= '9")) {
len = (len * 10) + (buf[i] - '0");
}
headers.addHeader(HTTPConstants.HEADER_CONTENT_LENGTH, String.valueOf(len));
} else if (endHeaderIndex == actionLen
&& matches(buf, actionHeader)) {
soapAction.delete(0, soapAction.length());
// skip initial '"'
i++;
while ((++i < n) && (buf[i] != '"")) {
soapAction.append((char) (buf[i] & 0x7f));
}
headers.addHeader(HTTPConstants.HEADER_SOAP_ACTION, "\"" + soapAction.toString() + "\"");
} else if (server.isSessionUsed() && endHeaderIndex == cookieLen
&& matches(buf, cookieHeader)) {
// keep everything up to first ;
while ((++i < n) && (buf[i] != ';") && (buf[i] != '\r") && (buf[i] != '\n")) {
cookie.append((char) (buf[i] & 0x7f));
}
headers.addHeader("Set-Cookie", cookie.toString());
} else if (server.isSessionUsed() && endHeaderIndex == cookie2Len
&& matches(buf, cookie2Header)) {
// keep everything up to first ;
while ((++i < n) && (buf[i] != ';") && (buf[i] != '\r") && (buf[i] != '\n")) {
cookie2.append((char) (buf[i] & 0x7f));
}
headers.addHeader("Set-Cookie2", cookie.toString());
} else if (endHeaderIndex == authLen && matches(buf, authHeader)) {
if (matches(buf, endHeaderIndex, basicAuth)) {
i += basicAuth.length;
while (++i < n && (buf[i] != '\r") && (buf[i] != '\n")) {
if (buf[i] == ' ") continue;
authInfo.append((char) (buf[i] & 0x7f));
}
headers.addHeader(HTTPConstants.HEADER_AUTHORIZATION, new String(basicAuth) + authInfo.toString());
} else {
throw new java.io.IOException(
Messages.getMessage("badAuth00"));
}
} else if (endHeaderIndex == locationLen && matches(buf, locationHeader)) {
while (++i < n && (buf[i] != '\r") && (buf[i] != '\n")) {
if (buf[i] == ' ") continue;
contentLocation.append((char) (buf[i] & 0x7f));
}
headers.addHeader(HTTPConstants.HEADER_CONTENT_LOCATION, contentLocation.toString());
} else if (endHeaderIndex == typeLen && matches(buf, typeHeader)) {
while (++i < n && (buf[i] != '\r") && (buf[i] != '\n")) {
if (buf[i] == ' ") continue;
contentType.append((char) (buf[i] & 0x7f));
}
headers.addHeader(HTTPConstants.HEADER_CONTENT_TYPE, contentLocation.toString());
} else {
String customHeaderName = new String(buf, 0, endHeaderIndex - 2);
StringBuffer customHeaderValue = new StringBuffer();
while (++i < n && (buf[i] != '\r") && (buf[i] != '\n")) {
if (buf[i] == ' ") continue;
customHeaderValue.append((char) (buf[i] & 0x7f));
}
headers.addHeader(customHeaderName, customHeaderValue.toString());
}
}
return len;
| private void | putInt(byte[] buf, java.io.OutputStream out, int value)output an integer into the output stream
int len = 0;
int offset = buf.length;
// negative numbers
if (value < 0) {
buf[--offset] = (byte) '-";
value = -value;
len++;
}
// zero
if (value == 0) {
buf[--offset] = (byte) '0";
len++;
}
// positive numbers
while (value > 0) {
buf[--offset] = (byte) (value % 10 + '0");
value = value / 10;
len++;
}
// write the result
out.write(buf, offset, len);
| private int | readLine(NonBlockingBufferedInputStream is, byte[] b, int off, int len)Read a single line from the input stream
int count = 0, c;
while ((c = is.read()) != -1) {
if (c != '\n" && c != '\r") {
b[off++] = (byte) c;
count++;
}
if (count == len) break;
if ('\n" == c) {
int peek = is.peek(); //If the next line begins with tab or space then this is a continuation.
if (peek != ' " && peek != '\t") break;
}
}
return count > 0 ? count : -1;
| public void | run()Run method
try {
execute();
} finally {
SimpleAxisServer.getPool().workerDone(this, false);
}
|
|