All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.axis.transport.http.AxisServlet Maven / Gradle / Ivy

/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.axis.transport.http;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;

import org.apache.axis.AxisEngine;
import org.apache.axis.AxisFault;
import org.apache.axis.ConfigurationException;
import org.apache.axis.Constants;
import org.apache.axis.Handler;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.SimpleTargetedChain;
import org.apache.axis.client.Service;
import org.apache.axis.management.ServiceAdmin;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.description.ServiceDesc;
import org.apache.axis.handlers.soap.SOAPService;
import org.apache.axis.security.servlet.ServletSecurityProvider;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.XMLUtils;
import org.apache.commons.logging.Log;
import org.w3c.dom.Element;

/**
 *
 * @author Doug Davis ([email protected])
 * @author Steve Loughran
 * xdoclet tags are not active yet; keep web.xml in sync.
 * To change the location of the services, change url-pattern in web.xml and
 * set parameter axis.servicesPath in server-config.wsdd. For more information see
 * Axis Reference Guide.
 *
 * @web.servlet name="AxisServlet"  display-name="Apache-Axis Servlet"
 * @web.servlet-mapping url-pattern="/servlet/AxisServlet"
 * @web.servlet-mapping url-pattern="*.jws"
 * @web.servlet-mapping url-pattern="/services/*"
  */
public class AxisServlet extends AxisServletBase {
    protected static Log log =
            LogFactory.getLog(AxisServlet.class.getName());

    /**
     * this log is for timing
     */
    private static Log tlog =
            LogFactory.getLog(Constants.TIME_LOG_CATEGORY);

    /**
     * a separate log for exceptions lets users route them
     * differently from general low level debug info
     */
    private static Log exceptionLog =
            LogFactory.getLog(Constants.EXCEPTION_LOG_CATEGORY);

    public static final String INIT_PROPERTY_TRANSPORT_NAME =
            "transport.name";

    public static final String INIT_PROPERTY_USE_SECURITY =
            "use-servlet-security";
    public static final String INIT_PROPERTY_ENABLE_LIST =
            "axis.enableListQuery";

    public static final String INIT_PROPERTY_JWS_CLASS_DIR =
            "axis.jws.servletClassDir";

    // This will turn off the list of available services
    public static final String INIT_PROPERTY_DISABLE_SERVICES_LIST =
            "axis.disableServiceList";

    // Location of the services as defined by the servlet-mapping in web.xml
    public static final String INIT_PROPERTY_SERVICES_PATH =
            "axis.servicesPath";

    // These have default values.
    private String transportName;

    private Handler transport;

    private ServletSecurityProvider securityProvider = null;

    private String servicesPath;

    /**
     * cache of logging debug option; only evaluated at init time.
     * So no dynamic switching of logging options with this servlet.
     */
    private static boolean isDebug = false;

    /**
     * Should we enable the "?list" functionality on GETs?  (off by
     * default because deployment information is a potential security
     * hole)
     */
    private boolean enableList = false;

    /**
     * Should we turn off the list of services when we receive a GET
     * at the servlet root?
     */
    private boolean disableServicesList = false;

    /**
     * Cached path to JWS output directory
     */
    private String jwsClassDir = null;
    protected String getJWSClassDir() {return jwsClassDir;
    }


    /**
     * create a new servlet instance
     */
    public AxisServlet() {
    }

    /**
     * Initialization method.
     */
    public void init() throws javax.servlet.ServletException {
        super.init();
        ServletContext context = getServletConfig().getServletContext();

        isDebug = log.isDebugEnabled();
        if (isDebug) {
            log.debug("In servlet init");
        }
        transportName = getOption(context,
                                  INIT_PROPERTY_TRANSPORT_NAME,
                                  HTTPTransport.DEFAULT_TRANSPORT_NAME);

        if (JavaUtils.isTrueExplicitly(getOption(context,
                                                 INIT_PROPERTY_USE_SECURITY, null))) {
            securityProvider = new ServletSecurityProvider();
        }

        enableList =
                JavaUtils.isTrueExplicitly(getOption(context,
                INIT_PROPERTY_ENABLE_LIST, null));

        jwsClassDir = getOption(context, INIT_PROPERTY_JWS_CLASS_DIR, null);

        // Should we list services?
        disableServicesList = JavaUtils.isTrue(getOption(context,
                INIT_PROPERTY_DISABLE_SERVICES_LIST, "false"));

        servicesPath = getOption(context, INIT_PROPERTY_SERVICES_PATH,
                                 "/services/");

        /**
         * There are DEFINATE problems here if
         * getHomeDir and/or getDefaultJWSClassDir return null
         * (as they could with WebLogic).
         * This needs to be reexamined in the future, but this
         * should fix any NPE's in the mean time.
         */
        if (jwsClassDir != null) {
            if (getHomeDir() != null) {
                jwsClassDir = getHomeDir() + jwsClassDir;
            }
        } else {
            jwsClassDir = getDefaultJWSClassDir();
        }

        initQueryStringHandlers();

        // Setup the service admin
        try {
            ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo());
        } catch (AxisFault af) {
            exceptionLog.info("Exception setting AxisEngine on ServiceAdmin " +
                              af);
        }
    }


    /**
     * Process GET requests. This includes handoff of pseudo-SOAP requests
     *
     * @param request request in
     * @param response request out
     * @throws ServletException
     * @throws IOException
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws
            ServletException, IOException {
        if (isDebug) {
            log.debug("Enter: doGet()");

        }
        PrintWriter writer = new FilterPrintWriter(response);

        try {
            AxisEngine engine = getEngine();
            ServletContext servletContext =
                    getServletConfig().getServletContext();

            String pathInfo = request.getPathInfo();
            String realpath = servletContext.getRealPath(request.getServletPath());
            if (realpath == null) {
                realpath = request.getServletPath();
            }

            //JWS pages are special; they are the servlet path and there
            //is no pathinfo...we map the pathinfo to the servlet path to keep
            //it happy
            boolean isJWSPage = request.getRequestURI().endsWith(".jws");
            if (isJWSPage) {
                pathInfo = request.getServletPath();
            }

            // Try to execute a query string plugin and return upon success.

            if (processQuery(request, response, writer) == true) {
                return;
            }

            boolean hasNoPath = (pathInfo == null || pathInfo.equals(""));
            if (!disableServicesList) {
                if(hasNoPath) {
                    // If the user requested the servlet (i.e. /axis/servlet/AxisServlet)
                    // with no service name, present the user with a list of deployed
                    // services to be helpful
                    // Don't do this if has been turned off
                    reportAvailableServices(response, writer, request);
                } else if (realpath != null) {
                    // We have a pathname, so now we perform WSDL or list operations

                    // get message context w/ various properties set
                    MessageContext msgContext = createMessageContext(engine,
                            request, response);

                    // NOTE:  HttpUtils.getRequestURL has been deprecated.
                    // This line SHOULD be:
                    //    String url = req.getRequestURL().toString()
                    // HOWEVER!!!!  DON'T REPLACE IT!  There's a bug in
                    // req.getRequestURL that is not in HttpUtils.getRequestURL
                    // req.getRequestURL returns "localhost" in the remote
                    // scenario rather than the actual host name.
                    //
                    // But more importantly, getRequestURL() is a servlet 2.3
                    // API and to support servlet 2.2 (aka WebSphere 4)
                    // we need to leave this in for a while longer. tomj 10/14/2004
                    //
                    String url = HttpUtils.getRequestURL(request).toString();

                    msgContext.setProperty(MessageContext.TRANS_URL, url);

                    // See if we can locate the desired service.  If we
                    // can't, return a 404 Not Found.  Otherwise, just
                    // print the placeholder message.

                    String serviceName;
                    if (pathInfo.startsWith("/")) {
                        serviceName = pathInfo.substring(1);
                    } else {
                        serviceName = pathInfo;
                    }

                    SOAPService s = engine.getService(serviceName);
                    if (s == null) {
                        //no service: report it
                        if (isJWSPage) {
                            reportCantGetJWSService(request, response, writer);
                        } else {
                            reportCantGetAxisService(request, response, writer);
                        }

                    } else {
                        //print a snippet of service info.
                        reportServiceInfo(response, writer, s, serviceName);
                    }
                }
            } else {
                // We didn't have a real path in the request, so just
                // print a message informing the user that they reached
                // the servlet.

                response.setContentType("text/html; charset=utf-8");
                writer.println("

Axis HTTP Servlet

"); writer.println(Messages.getMessage("reachedServlet00")); writer.println("

" + Messages.getMessage("transportName00", "" + transportName + "")); writer.println(""); } } catch (AxisFault fault) { reportTroubleInGet(fault, response, writer); } catch (Exception e) { reportTroubleInGet(e, response, writer); } finally { writer.close(); if (isDebug) { log.debug("Exit: doGet()"); } } } /** * when we get an exception or an axis fault in a GET, we handle * it almost identically: we go 'something went wrong', set the response * code to 500 and then dump info. But we dump different info for an axis fault * or subclass thereof. * @param exception what went wrong * @param response current response * @param writer open writer to response */ private void reportTroubleInGet(Throwable exception, HttpServletResponse response, PrintWriter writer) { response.setContentType("text/html; charset=utf-8"); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); writer.println("

" + Messages.getMessage("error00") + "

"); writer.println("

" + Messages.getMessage("somethingWrong00") + "

"); if (exception instanceof AxisFault) { AxisFault fault = (AxisFault) exception; processAxisFault(fault); writeFault(writer, fault); } else { logException(exception); writer.println("
Exception - " + exception + "
"); //dev systems only give fault dumps if (isDevelopment()) { writer.println(JavaUtils.stackToString(exception)); } writer.println("
"); } } /** * routine called whenever an axis fault is caught; where they * are logged and any other business. The method may modify the fault * in the process * @param fault what went wrong. */ protected void processAxisFault(AxisFault fault) { //log the fault Element runtimeException = fault.lookupFaultDetail( Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION); if (runtimeException != null) { exceptionLog.info(Messages.getMessage("axisFault00"), fault); //strip runtime details fault.removeFaultDetail(Constants. QNAME_FAULTDETAIL_RUNTIMEEXCEPTION); } else if (exceptionLog.isDebugEnabled()) { exceptionLog.debug(Messages.getMessage("axisFault00"), fault); } //dev systems only give fault dumps if (!isDevelopment()) { //strip out the stack trace fault.removeFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE); } } /** * log any exception to our output log, at our chosen level * @param e what went wrong */ protected void logException(Throwable e) { exceptionLog.info(Messages.getMessage("exception00"), e); } /** * this method writes a fault out to an HTML stream. This includes * escaping the strings to defend against cross-site scripting attacks * @param writer * @param axisFault */ private void writeFault(PrintWriter writer, AxisFault axisFault) { String localizedMessage = XMLUtils.xmlEncodeString(axisFault. getLocalizedMessage()); writer.println("
Fault - " + localizedMessage + "
"); writer.println(axisFault.dumpToString()); writer.println("
"); } /** * print a snippet of service info. * @param service service * @param writer output channel * @param serviceName where to put stuff */ protected void reportServiceInfo(HttpServletResponse response, PrintWriter writer, SOAPService service, String serviceName) { response.setContentType("text/html; charset=utf-8"); writer.println("

" + service.getName() + "

"); writer.println( "

" + Messages.getMessage("axisService00") + "

"); writer.println( "" + Messages.getMessage("perhaps00") + ""); } /** * report that we have no WSDL * * This method was moved to the querystring handler QSWSDLHandler. The * method reportNoWSDL in AxisServlet is never called. Perhaps the method * is overwritten in subclasses of AxisServlet so the method wasn't * removed. See the discussion in * * http://nagoya.apache.org/bugzilla/show_bug.cgi?id=23845 * * @param res * @param writer * @param moreDetailCode optional name of a message to provide more detail * @param axisFault optional fault string, for extra info at debug time only */ protected void reportNoWSDL(HttpServletResponse res, PrintWriter writer, String moreDetailCode, AxisFault axisFault) { } /** * This method lists the available services; it is called when there is * nothing to execute on a GET * @param response * @param writer * @param request * @throws ConfigurationException * @throws AxisFault */ protected void reportAvailableServices(HttpServletResponse response, PrintWriter writer, HttpServletRequest request) throws ConfigurationException, AxisFault { AxisEngine engine = getEngine(); response.setContentType("text/html; charset=utf-8"); writer.println("

And now... Some Services

"); Iterator i; try { i = engine.getConfig().getDeployedServices(); } catch (ConfigurationException configException) { //turn any internal configuration exceptions back into axis faults //if that is what they are if (configException.getContainedException() instanceof AxisFault) { throw (AxisFault) configException.getContainedException(); } else { throw configException; } } // baseURL may change if tag is used for // custom deployment at a different location String defaultBaseURL = getWebappBase(request) + servicesPath; writer.println("
    "); while (i.hasNext()) { ServiceDesc sd = (ServiceDesc) i.next(); StringBuffer sb = new StringBuffer(); sb.append("
  • "); String name = sd.getName(); sb.append(name); sb.append(" (wsdl)
  • "); writer.println(sb.toString()); ArrayList operations = sd.getOperations(); if (!operations.isEmpty()) { writer.println("
      "); for (Iterator it = operations.iterator(); it.hasNext(); ) { OperationDesc desc = (OperationDesc) it.next(); writer.println("
    • " + desc.getName()); } writer.println("
    "); } } writer.println("
"); } /** * generate the error response to indicate that there is apparently no endpoint there * @param request the request that didnt have an edpoint * @param response response we are generating * @param writer open writer for the request */ protected void reportCantGetAxisService(HttpServletRequest request, HttpServletResponse response, PrintWriter writer) { // no such service.... response.setStatus(HttpURLConnection.HTTP_NOT_FOUND); response.setContentType("text/html; charset=utf-8"); writer.println("

" + Messages.getMessage("error00") + "

"); writer.println("

" + Messages.getMessage("noService06") + "

"); } /** * probe for a JWS page and report 'no service' if one is not found there * @param request the request that didnt have an edpoint * @param response response we are generating * @param writer open writer for the request */ protected void reportCantGetJWSService(HttpServletRequest request, HttpServletResponse response, PrintWriter writer) { // first look to see if there is a service // requestPath is a work around to support serving .jws web services // from services URL - see AXIS-843 for more information String requestPath = request.getServletPath() + ((request.getPathInfo() != null) ? request.getPathInfo() : ""); String realpath = getServletConfig().getServletContext() .getRealPath(requestPath); log.debug("JWS real path: " + realpath); boolean foundJWSFile = (new File(realpath).exists()) && (realpath.endsWith(Constants. JWS_DEFAULT_FILE_EXTENSION)); response.setContentType("text/html; charset=utf-8"); if (foundJWSFile) { response.setStatus(HttpURLConnection.HTTP_OK); writer.println(Messages.getMessage("foundJWS00") + "

"); String url = request.getRequestURI(); String urltext = Messages.getMessage("foundJWS01"); writer.println("" + urltext + ""); } else { response.setStatus(HttpURLConnection.HTTP_NOT_FOUND); writer.println(Messages.getMessage("noService06")); } } /** * Process a POST to the servlet by handing it off to the Axis Engine. * Here is where SOAP messages are received * @param req posted request * @param res respose * @throws ServletException trouble * @throws IOException different trouble */ public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { long t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0; String soapAction = null; MessageContext msgContext = null; if (isDebug) { log.debug("Enter: doPost()"); } if (tlog.isDebugEnabled()) { t0 = System.currentTimeMillis(); } Message responseMsg = null; String contentType = null; try { AxisEngine engine = getEngine(); if (engine == null) { // !!! should return a SOAP fault... ServletException se = new ServletException(Messages.getMessage("noEngine00")); log.debug("No Engine!", se); throw se; } res.setBufferSize(1024 * 8); // provide performance boost. /** get message context w/ various properties set */ msgContext = createMessageContext(engine, req, res); // ? OK to move this to 'getMessageContext', // ? where it would also be picked up for 'doGet()' ? if (securityProvider != null) { if (isDebug) { log.debug("securityProvider:" + securityProvider); } msgContext.setProperty(MessageContext.SECURITY_PROVIDER, securityProvider); } /* Get request message */ Message requestMsg = new Message(req.getInputStream(), false, req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE), req.getHeader(HTTPConstants. HEADER_CONTENT_LOCATION)); // Transfer HTTP headers to MIME headers for request message. MimeHeaders requestMimeHeaders = requestMsg.getMimeHeaders(); for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) { String headerName = (String) e.nextElement(); for (Enumeration f = req.getHeaders(headerName); f.hasMoreElements(); ) { String headerValue = (String) f.nextElement(); requestMimeHeaders.addHeader(headerName, headerValue); } } if (isDebug) { log.debug("Request Message:" + requestMsg); /* Set the request(incoming) message field in the context */ /**********************************************************/ } msgContext.setRequestMessage(requestMsg); String url = HttpUtils.getRequestURL(req).toString(); msgContext.setProperty(MessageContext.TRANS_URL, url); // put character encoding of request to message context // in order to reuse it during the whole process. String requestEncoding; try { requestEncoding = (String) requestMsg.getProperty(SOAPMessage. CHARACTER_SET_ENCODING); if (requestEncoding != null) { msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, requestEncoding); } } catch (SOAPException e1) { } try { /** * Save the SOAPAction header in the MessageContext bag. * This will be used to tell the Axis Engine which service * is being invoked. This will save us the trouble of * having to parse the Request message - although we will * need to double-check later on that the SOAPAction header * does in fact match the URI in the body. */ // (is this last stmt true??? (I don't think so - Glen)) /********************************************************/ soapAction = getSoapAction(req); if (soapAction != null) { msgContext.setUseSOAPAction(true); msgContext.setSOAPActionURI(soapAction); } // Create a Session wrapper for the HTTP session. // These can/should be pooled at some point. // (Sam is Watching! :-) msgContext.setSession(new AxisHttpSession(req)); if (tlog.isDebugEnabled()) { t1 = System.currentTimeMillis(); } /* Invoke the Axis engine... */ /*****************************/ if (isDebug) { log.debug("Invoking Axis Engine."); //here we run the message by the engine } engine.invoke(msgContext); if (isDebug) { log.debug("Return from Axis Engine."); } if (tlog.isDebugEnabled()) { t2 = System.currentTimeMillis(); } responseMsg = msgContext.getResponseMessage(); // We used to throw exceptions on null response messages. // They are actually OK in certain situations (asynchronous // services), so fall through here and return an ACCEPTED // status code below. Might want to install a configurable // error check for this later. } catch (AxisFault fault) { //log and sanitize processAxisFault(fault); configureResponseFromAxisFault(res, fault); responseMsg = msgContext.getResponseMessage(); if (responseMsg == null) { responseMsg = new Message(fault); ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()). getMessage().setMessageContext(msgContext); } } catch (Exception e) { //other exceptions are internal trouble responseMsg = msgContext.getResponseMessage(); res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); responseMsg = convertExceptionToAxisFault(e, responseMsg); ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()). getMessage().setMessageContext(msgContext); } catch (Throwable t) { logException(t); //other exceptions are internal trouble responseMsg = msgContext.getResponseMessage(); res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); responseMsg = new Message(new AxisFault(t.toString(),t)); ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()). getMessage().setMessageContext(msgContext); } } catch (AxisFault fault) { processAxisFault(fault); configureResponseFromAxisFault(res, fault); responseMsg = msgContext.getResponseMessage(); if (responseMsg == null) { responseMsg = new Message(fault); ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()). getMessage().setMessageContext(msgContext); } } if (tlog.isDebugEnabled()) { t3 = System.currentTimeMillis(); } /* Send response back along the wire... */ /***********************************/ if (responseMsg != null) { // Transfer MIME headers to HTTP headers for response message. MimeHeaders responseMimeHeaders = responseMsg.getMimeHeaders(); for (Iterator i = responseMimeHeaders.getAllHeaders(); i.hasNext(); ) { MimeHeader responseMimeHeader = (MimeHeader) i.next(); res.addHeader(responseMimeHeader.getName(), responseMimeHeader.getValue()); } // synchronize the character encoding of request and response String responseEncoding = (String) msgContext.getProperty( SOAPMessage.CHARACTER_SET_ENCODING); if (responseEncoding != null) { try { responseMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, responseEncoding); } catch (SOAPException e) { } } //determine content type from message response contentType = responseMsg.getContentType(msgContext. getSOAPConstants()); sendResponse(contentType, res, responseMsg); } else { // No content, so just indicate accepted res.setStatus(202); } if (isDebug) { log.debug("Response sent."); log.debug("Exit: doPost()"); } if (tlog.isDebugEnabled()) { t4 = System.currentTimeMillis(); tlog.debug("axisServlet.doPost: " + soapAction + " pre=" + (t1 - t0) + " invoke=" + (t2 - t1) + " post=" + (t3 - t2) + " send=" + (t4 - t3) + " " + msgContext.getTargetService() + "." + ((msgContext.getOperation() == null) ? "" : msgContext.getOperation().getName())); } } /** * Configure the servlet response status code and maybe other headers * from the fault info. * @param response response to configure * @param fault what went wrong */ private void configureResponseFromAxisFault(HttpServletResponse response, AxisFault fault) { // then get the status code // It's been suggested that a lack of SOAPAction // should produce some other error code (in the 400s)... int status = getHttpServletResponseStatus(fault); if (status == HttpServletResponse.SC_UNAUTHORIZED) { // unauth access results in authentication request // TODO: less generic realm choice? response.setHeader("WWW-Authenticate", "Basic realm=\"AXIS\""); } response.setStatus(status); } /** * turn any Exception into an AxisFault, log it, set the response * status code according to what the specifications say and * return a response message for posting. This will be the response * message passed in if non-null; one generated from the fault otherwise. * * @param exception what went wrong * @param responseMsg what response we have (if any) * @return a response message to send to the user */ private Message convertExceptionToAxisFault(Exception exception, Message responseMsg) { logException(exception); if (responseMsg == null) { AxisFault fault = AxisFault.makeFault(exception); processAxisFault(fault); responseMsg = new Message(fault); } return responseMsg; } /** * Extract information from AxisFault and map it to a HTTP Status code. * * @param af Axis Fault * @return HTTP Status code. */ protected int getHttpServletResponseStatus(AxisFault af) { // TODO: Should really be doing this with explicit AxisFault // subclasses... --Glen return af.getFaultCode().getLocalPart().startsWith("Server.Unauth") ? HttpServletResponse.SC_UNAUTHORIZED : HttpServletResponse.SC_INTERNAL_SERVER_ERROR; // This will raise a 401 for both // "Unauthenticated" & "Unauthorized"... } /** * write a message to the response, set appropriate headers for content * type..etc. * @param res response * @param responseMsg message to write * @throws AxisFault * @throws IOException if the response stream can not be written to */ private void sendResponse(String contentType, HttpServletResponse res, Message responseMsg) throws AxisFault, IOException { if (responseMsg == null) { res.setStatus(HttpServletResponse.SC_NO_CONTENT); if (isDebug) { log.debug("NO AXIS MESSAGE TO RETURN!"); //String resp = Messages.getMessage("noData00"); //res.setContentLength((int) resp.getBytes().length); //res.getWriter().print(resp); } } else { if (isDebug) { log.debug("Returned Content-Type:" + contentType); // log.debug("Returned Content-Length:" + // responseMsg.getContentLength()); } try { res.setContentType(contentType); /* My understand of Content-Length * HTTP 1.0 * -Required for requests, but optional for responses. * HTTP 1.1 * - Either Content-Length or HTTP Chunking is required. * Most servlet engines will do chunking if content-length is not specified. * * */ //if(clientVersion == HTTPConstants.HEADER_PROTOCOL_V10) //do chunking if necessary. // res.setContentLength(responseMsg.getContentLength()); responseMsg.writeTo(res.getOutputStream()); } catch (SOAPException e) { logException(e); } } if (!res.isCommitted()) { res.flushBuffer(); // Force it right now. } } /** * Place the Request message in the MessagContext object - notice * that we just leave it as a 'ServletRequest' object and let the * Message processing routine convert it - we don't do it since we * don't know how it's going to be used - perhaps it might not * even need to be parsed. * @return a message context */ private MessageContext createMessageContext(AxisEngine engine, HttpServletRequest req, HttpServletResponse res) { MessageContext msgContext = new MessageContext(engine); String requestPath = getRequestPath(req); if (isDebug) { log.debug("MessageContext:" + msgContext); log.debug("HEADER_CONTENT_TYPE:" + req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE)); log.debug("HEADER_CONTENT_LOCATION:" + req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION)); log.debug("Constants.MC_HOME_DIR:" + String.valueOf(getHomeDir())); log.debug("Constants.MC_RELATIVE_PATH:" + requestPath); log.debug("HTTPConstants.MC_HTTP_SERVLETLOCATION:" + String.valueOf(getWebInfPath())); log.debug("HTTPConstants.MC_HTTP_SERVLETPATHINFO:" + req.getPathInfo()); log.debug("HTTPConstants.HEADER_AUTHORIZATION:" + req.getHeader(HTTPConstants.HEADER_AUTHORIZATION)); log.debug("Constants.MC_REMOTE_ADDR:" + req.getRemoteAddr()); log.debug("configPath:" + String.valueOf(getWebInfPath())); } /* Set the Transport */ /*********************/ msgContext.setTransportName(transportName); /* Save some HTTP specific info in the bag in case someone needs it */ /********************************************************************/ msgContext.setProperty(Constants.MC_JWS_CLASSDIR, jwsClassDir); msgContext.setProperty(Constants.MC_HOME_DIR, getHomeDir()); msgContext.setProperty(Constants.MC_RELATIVE_PATH, requestPath); msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLET, this); msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, req); msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, res); msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETLOCATION, getWebInfPath()); msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO, req.getPathInfo()); msgContext.setProperty(HTTPConstants.HEADER_AUTHORIZATION, req.getHeader(HTTPConstants.HEADER_AUTHORIZATION)); msgContext.setProperty(Constants.MC_REMOTE_ADDR, req.getRemoteAddr()); // Set up a javax.xml.rpc.server.ServletEndpointContext ServletEndpointContextImpl sec = new ServletEndpointContextImpl(); msgContext.setProperty(Constants.MC_SERVLET_ENDPOINT_CONTEXT, sec); /* Save the real path */ /**********************/ String realpath = getServletConfig().getServletContext() .getRealPath(requestPath); if (realpath != null) { msgContext.setProperty(Constants.MC_REALPATH, realpath); } msgContext.setProperty(Constants.MC_CONFIGPATH, getWebInfPath()); return msgContext; } /** * Extract the SOAPAction header. * if SOAPAction is null then we'll we be forced to scan the body for it. * if SOAPAction is "" then use the URL * @param req incoming request * @return the action * @throws AxisFault */ private String getSoapAction(HttpServletRequest req) throws AxisFault { String soapAction = req.getHeader(HTTPConstants.HEADER_SOAP_ACTION); if (soapAction == null) { String contentType = req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE); if(contentType != null) { int index = contentType.indexOf("action"); if(index != -1){ soapAction = contentType.substring(index + 7); } } } if (isDebug) { log.debug("HEADER_SOAP_ACTION:" + soapAction); /** * Technically, if we don't find this header, we should probably fault. * It's required in the SOAP HTTP binding. */ } if (soapAction == null) { AxisFault af = new AxisFault("Client.NoSOAPAction", Messages.getMessage("noHeader00", "SOAPAction"), null, null); exceptionLog.error(Messages.getMessage("genFault00"), af); throw af; } // the SOAP 1.1 spec & WS-I 1.0 says: // soapaction = "SOAPAction" ":" [ <"> URI-reference <"> ] // some implementations leave off the quotes // we strip them if they are present if (soapAction.startsWith("\"") && soapAction.endsWith("\"") && soapAction.length() >= 2) { int end = soapAction.length() - 1; soapAction = soapAction.substring(1, end); } if (soapAction.length() == 0) { soapAction = req.getContextPath(); // Is this right? } return soapAction; } /** * Provided to allow overload of default JWSClassDir * by derived class. * @return directory for JWS files */ protected String getDefaultJWSClassDir() { return (getWebInfPath() == null) ? null // ??? what is a good FINAL default for WebLogic? : getWebInfPath() + File.separator + "jwsClasses"; } /** * Initialize a Handler for the transport defined in the Axis server config. * This includes optionally filling in query string handlers. */ public void initQueryStringHandlers() { try { this.transport = getEngine().getTransport(this.transportName); if (this.transport == null) { // No transport by this name is defined. Therefore, fill in default // query string handlers. this.transport = new SimpleTargetedChain(); this.transport.setOption("qs.list", "org.apache.axis.transport.http.QSListHandler"); this.transport.setOption("qs.method", "org.apache.axis.transport.http.QSMethodHandler"); this.transport.setOption("qs.wsdl", "org.apache.axis.transport.http.QSWSDLHandler"); return; } else { // See if we should use the default query string handlers. // By default, set this to true (for backwards compatibility). boolean defaultQueryStrings = true; String useDefaults = (String)this.transport.getOption( "useDefaultQueryStrings"); if ((useDefaults != null) && useDefaults.toLowerCase().equals("false")) { defaultQueryStrings = false; } if (defaultQueryStrings == true) { // We should use defaults, so fill them in. this.transport.setOption("qs.list", "org.apache.axis.transport.http.QSListHandler"); this.transport.setOption("qs.method", "org.apache.axis.transport.http.QSMethodHandler"); this.transport.setOption("qs.wsdl", "org.apache.axis.transport.http.QSWSDLHandler"); } } } catch (AxisFault e) { // Some sort of problem occurred, let's just make a default transport. this.transport = new SimpleTargetedChain(); this.transport.setOption("qs.list", "org.apache.axis.transport.http.QSListHandler"); this.transport.setOption("qs.method", "org.apache.axis.transport.http.QSMethodHandler"); this.transport.setOption("qs.wsdl", "org.apache.axis.transport.http.QSWSDLHandler"); return; } } /** * Attempts to invoke a plugin for the query string supplied in the URL. * * @param request the servlet's HttpServletRequest object. * @param response the servlet's HttpServletResponse object. * @param writer the servlet's PrintWriter object. */ private boolean processQuery(HttpServletRequest request, HttpServletResponse response, PrintWriter writer) throws AxisFault { // Attempt to instantiate a plug-in handler class for the query string // handler classes defined in the HTTP transport. String path = request.getServletPath(); String queryString = request.getQueryString(); String serviceName; AxisEngine engine = getEngine(); Iterator i = this.transport.getOptions().keySet().iterator(); if (queryString == null) { return false; } String servletURI = request.getContextPath() + path; String reqURI = request.getRequestURI(); // chop off '/'. if (servletURI.length() + 1 < reqURI.length()) { serviceName = reqURI.substring(servletURI.length() + 1); } else { serviceName = ""; } while (i.hasNext() == true) { String queryHandler = (String) i.next(); if (queryHandler.startsWith("qs.") == true) { // Only attempt to match the query string with transport // parameters prefixed with "qs:". String handlerName = queryHandler.substring (queryHandler.indexOf(".") + 1). toLowerCase(); // Determine the name of the plugin to invoke by using all text // in the query string up to the first occurence of &, =, or the // whole string if neither is present. int length = 0; boolean firstParamFound = false; while (firstParamFound == false && length < queryString.length()) { char ch = queryString.charAt(length++); if (ch == '&' || ch == '=') { firstParamFound = true; --length; } } if (length < queryString.length()) { queryString = queryString.substring(0, length); } if (queryString.toLowerCase().equals(handlerName) == true) { // Query string matches a defined query string handler name. // If the defined class name for this query string handler is blank, // just return (the handler is "turned off" in effect). if (this.transport.getOption(queryHandler).equals("")) { return false; } try { // Attempt to dynamically load the query string handler // and its "invoke" method. MessageContext msgContext = createMessageContext(engine, request, response); Class plugin = Class.forName((String)this.transport. getOption(queryHandler)); Method pluginMethod = plugin.getDeclaredMethod("invoke", new Class[] {msgContext.getClass()}); String url = HttpUtils.getRequestURL(request).toString(); // Place various useful servlet-related objects in // the MessageContext object being delivered to the // plugin. msgContext.setProperty(MessageContext.TRANS_URL, url); msgContext.setProperty(HTTPConstants. PLUGIN_SERVICE_NAME, serviceName); msgContext.setProperty(HTTPConstants.PLUGIN_NAME, handlerName); msgContext.setProperty(HTTPConstants. PLUGIN_IS_DEVELOPMENT, new Boolean(isDevelopment())); msgContext.setProperty(HTTPConstants.PLUGIN_ENABLE_LIST, new Boolean(enableList)); msgContext.setProperty(HTTPConstants.PLUGIN_ENGINE, engine); msgContext.setProperty(HTTPConstants.PLUGIN_WRITER, writer); msgContext.setProperty(HTTPConstants.PLUGIN_LOG, log); msgContext.setProperty(HTTPConstants. PLUGIN_EXCEPTION_LOG, exceptionLog); // Invoke the plugin. pluginMethod.invoke(plugin.newInstance(), new Object[] {msgContext}); writer.close(); return true; } catch (InvocationTargetException ie) { reportTroubleInGet(ie.getTargetException(), response, writer); // return true to prevent any further processing return true; } catch (Exception e) { reportTroubleInGet(e, response, writer); // return true to prevent any further processing return true; } } } } return false; } /** * getRequestPath a returns request path for web service padded with * request.getPathInfo for web services served from /services directory. * This is a required to support serving .jws web services from /services * URL. See AXIS-843 for more information. * * @param request HttpServletRequest * @return String */ private static String getRequestPath(HttpServletRequest request) { return request.getServletPath() + ((request.getPathInfo() != null) ? request.getPathInfo() : ""); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy