FileDocCategorySizeDatePackage
SimpleAxisWorker.javaAPI DocApache Axis 1.432440Sat Apr 22 18:57:28 BST 2006org.apache.axis.transport.http

SimpleAxisWorker

public 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 voidexecute()
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.StringgetLocalHost()
One method for all host name lookups.

        return NetworkUtils.getLocalHostname();
    
protected voidinvokeMethodFromGet(java.lang.String methodName, java.lang.String args)


    
public booleanmatches(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 booleanmatches(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 intparseHeaders(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.

param
is InputStream to read from
param
contentType The content type.
param
contentLocation The content location
param
soapAction StringBuffer to return the soapAction into
param
httpRequest StringBuffer for GET / POST
param
cookie first cookie header (if doSessions)
param
cookie2 second cookie header (if doSessions)
param
headers HTTP headers to transfer to MIME headers
return
Content-Length

        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 voidputInt(byte[] buf, java.io.OutputStream out, int value)
output an integer into the output stream

param
out OutputStream to be written to
param
value Integer value to be written.

        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 intreadLine(NonBlockingBufferedInputStream is, byte[] b, int off, int len)
Read a single line from the input stream

param
is inputstream to read from
param
b byte array to read into
param
off starting offset into the byte array
param
len maximum number of bytes to read

        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 voidrun()
Run method

        try {
            execute();
        } finally {
            SimpleAxisServer.getPool().workerDone(this, false);
        }