Jetty
  1. Jetty
  2. JETTY-468

Can not have multiple CGI configurations within the same context

    Details

    • Type: Improvement Improvement
    • Status: Resolved Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 6.1.6
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None
    • Number of attachments :
      3

      Description

      I've run into a problem trying to configure two different CGI
      servlets within the same context under jetty 6.1.6.

      I'm trying to run two different types of scripts (perl and python)
      from the one directory. Unfortunately it seems that whichever is
      configured last always takes precedence.

      I will attach my xml configuration and two sample scripts after submitting this issue. With the given
      configuration the perl script will run successfully, but the python
      script has the syntax error below (which is the error shown when
      trying to run this script with perl).

      syntax error at /private/tmp/test/foo.py line 2, near "print"

      Reversing the order of the setInitParameter calls means that all
      scripts are run with python (causing failure in the opposite direction).

      It would be very useful to me if Jetty handled this configuration in such a way that it was possible to configure two separate commandPrefixes.

      1. JETTY-468.xml
        2 kB
        Matt Sheppard
      2. perl.pl
        0.1 kB
        Matt Sheppard
      3. python.py
        0.1 kB
        Matt Sheppard

        Activity

        Hide
        Matt Sheppard added a comment -

        Attached configuration and example perl and python scripts.

        Show
        Matt Sheppard added a comment - Attached configuration and example perl and python scripts.
        Matt Sheppard made changes -
        Field Original Value New Value
        Attachment perl.pl [ 30747 ]
        Attachment JETTY-468.xml [ 30746 ]
        Attachment python.py [ 30748 ]
        Hide
        Matt Sheppard added a comment -

        Subsequently posted on the jetty-suppot list. I'll look into this and report back.

        I think it is because Jetty gives the servlet a name based on the
        classname and the second overwrites the first so both mappings end up
        pointing to the same servlet instance.

        With Jetty xml you probably have to build the servlet first, give it a
        name and then pass it to the addServlet method.

        Alternatively if you configure the context as a standard web app and add
        the CGI servlets using a JEE standard web.xml descriptor you can supply
        different names for servlets with the same class which should work.

        <servlet>
        <servlet-name>php</servlet-name>
        <servlet-class>au.com.lastweekend.cgi.CGIServlet</servlet-class>
        <init-param>
        <param-name>CGI_commandPrefix</param-name>
        <param-value>/usr/bin/php-cgi</param-value>
        </init-param>
        </servlet>
        <servlet-mapping> <servlet-name>php</servlet-name>
        <url-pattern>*.php</url-pattern> </servlet-mapping>
        <servlet>
        <servlet-name>perl</servlet-name>
        <servlet-class>au.com.lastweekend.cgi.CGIServlet</servlet-class>
        <init-param>
        <param-name>CGI_commandPrefix</param-name>
        <param-value>/usr/bin/perl</param-value>
        </init-param>
        </servlet>
        <servlet-mapping> <servlet-name>perl</servlet-name>
        <url-pattern>*.pl</url-pattern> </servlet-mapping>

        Show
        Matt Sheppard added a comment - Subsequently posted on the jetty-suppot list. I'll look into this and report back. I think it is because Jetty gives the servlet a name based on the classname and the second overwrites the first so both mappings end up pointing to the same servlet instance. With Jetty xml you probably have to build the servlet first, give it a name and then pass it to the addServlet method. Alternatively if you configure the context as a standard web app and add the CGI servlets using a JEE standard web.xml descriptor you can supply different names for servlets with the same class which should work. <servlet> <servlet-name>php</servlet-name> <servlet-class>au.com.lastweekend.cgi.CGIServlet</servlet-class> <init-param> <param-name>CGI_commandPrefix</param-name> <param-value>/usr/bin/php-cgi</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>php</servlet-name> <url-pattern>*.php</url-pattern> </servlet-mapping> <servlet> <servlet-name>perl</servlet-name> <servlet-class>au.com.lastweekend.cgi.CGIServlet</servlet-class> <init-param> <param-name>CGI_commandPrefix</param-name> <param-value>/usr/bin/perl</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>perl</servlet-name> <url-pattern>*.pl</url-pattern> </servlet-mapping>
        Hide
        Matt Sheppard added a comment -

        Should have added - the above suggestion was from Grant Gardner <grant@lastweekend.com.au>

        Show
        Matt Sheppard added a comment - Should have added - the above suggestion was from Grant Gardner <grant@lastweekend.com.au>
        Hide
        Matt Sheppard added a comment -

        Based on Grant's suggestion, I got to the config below which does what I expect.

        I'm happy for this issue to be closed, but I'll leave it to be reviewed in case the originally described behaviour is not what the developers intended.

        <?xml version="1.0"?>
        <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//
        EN" "http://jetty.mortbay.org/configure.dtd">
        <Configure id="HttpServer" class="org.mortbay.jetty.Server">
        <Call name="addConnector">
        <Arg>
        <New class="org.mortbay.jetty.nio.SelectChannelConnector">
        <Set name="port">
        <SystemProperty name="jetty.port" default="8080"/>
        </Set>
        </New>
        </Arg>
        </Call>

        <Set name="handler">
        <New id="Handlers"
        class="org.mortbay.jetty.handler.HandlerCollection">
        <Set name="handlers">
        <Array type="org.mortbay.jetty.Handler">
        <Item>
        <New id="Contexts"
        class="org.mortbay.jetty.handler.ContextHandlerCollection"/>
        </Item>
        </Array>
        </Set>
        </New>
        </Set>

        <New class="org.mortbay.jetty.servlet.Context">
        <Arg>
        <Ref id="Contexts"/>
        </Arg>
        <Arg>
        <!-- Session handler -->
        </Arg>
        <Arg>
        <!-- Security handler -->
        </Arg>
        <Arg>
        <New class="org.mortbay.jetty.servlet.ServletHandler">
        <Call name="addServletWithMapping">
        <Arg>
        <New class="org.mortbay.jetty.servlet.ServletHolder">
        <Arg>
        <New class="org.mortbay.servlet.CGI">
        </New>
        </Arg>
        <Call name="setInitParameter">
        <Arg>commandPrefix</Arg>
        <Arg>/usr/bin/python</Arg>
        </Call>
        </New>
        </Arg>
        <Arg>*.py</Arg>
        </Call>
        <Call name="addServletWithMapping">
        <Arg>
        <New class="org.mortbay.jetty.servlet.ServletHolder">
        <Arg>
        <New class="org.mortbay.servlet.CGI">
        </New>
        </Arg>
        <Call name="setInitParameter">
        <Arg>commandPrefix</Arg>
        <Arg>/usr/bin/perl</Arg>
        </Call>
        </New>
        </Arg>
        <Arg>*.pl</Arg>
        </Call>
        </New>
        </Arg>
        <Arg>
        <!-- Error handler -->
        </Arg>
        <Set name="resourceBase">/tmp/test</Set>
        <Set name="contextPath">/</Set>
        </New>
        </Configure>

        Show
        Matt Sheppard added a comment - Based on Grant's suggestion, I got to the config below which does what I expect. I'm happy for this issue to be closed, but I'll leave it to be reviewed in case the originally described behaviour is not what the developers intended. <?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure// EN" "http://jetty.mortbay.org/configure.dtd"> <Configure id="HttpServer" class="org.mortbay.jetty.Server"> <Call name="addConnector"> <Arg> <New class="org.mortbay.jetty.nio.SelectChannelConnector"> <Set name="port"> <SystemProperty name="jetty.port" default="8080"/> </Set> </New> </Arg> </Call> <Set name="handler"> <New id="Handlers" class="org.mortbay.jetty.handler.HandlerCollection"> <Set name="handlers"> <Array type="org.mortbay.jetty.Handler"> <Item> <New id="Contexts" class="org.mortbay.jetty.handler.ContextHandlerCollection"/> </Item> </Array> </Set> </New> </Set> <New class="org.mortbay.jetty.servlet.Context"> <Arg> <Ref id="Contexts"/> </Arg> <Arg> <!-- Session handler --> </Arg> <Arg> <!-- Security handler --> </Arg> <Arg> <New class="org.mortbay.jetty.servlet.ServletHandler"> <Call name="addServletWithMapping"> <Arg> <New class="org.mortbay.jetty.servlet.ServletHolder"> <Arg> <New class="org.mortbay.servlet.CGI"> </New> </Arg> <Call name="setInitParameter"> <Arg>commandPrefix</Arg> <Arg>/usr/bin/python</Arg> </Call> </New> </Arg> <Arg>*.py</Arg> </Call> <Call name="addServletWithMapping"> <Arg> <New class="org.mortbay.jetty.servlet.ServletHolder"> <Arg> <New class="org.mortbay.servlet.CGI"> </New> </Arg> <Call name="setInitParameter"> <Arg>commandPrefix</Arg> <Arg>/usr/bin/perl</Arg> </Call> </New> </Arg> <Arg>*.pl</Arg> </Call> </New> </Arg> <Arg> <!-- Error handler --> </Arg> <Set name="resourceBase">/tmp/test</Set> <Set name="contextPath">/</Set> </New> </Configure>
        Hide
        Grant Gardner added a comment -

        Matt's new method works because ServletHolder.setServlet() contains the following

        if (getName()==null)
                    setName(servlet.getClass().getName()+"-"+super.hashCode());
        

        Doing something similar in ServletHandler

        public ServletHolder addServletWithMapping (String className,String pathSpec) {
            
        ...
        holder.setName(className + "-" + System.identityHashCode(holder));
        ...        
        }
        

        should work but perhaps the if(getName()==null) construct should also be done in Holder.setClassName()

        Show
        Grant Gardner added a comment - Matt's new method works because ServletHolder.setServlet() contains the following if (getName()== null ) setName(servlet.getClass().getName()+ "-" + super .hashCode()); Doing something similar in ServletHandler public ServletHolder addServletWithMapping ( String className, String pathSpec) { ... holder.setName(className + "-" + System .identityHashCode(holder)); ... } should work but perhaps the if(getName()==null) construct should also be done in Holder.setClassName()
        Hide
        Greg Wilkins added a comment -

        Note that you can always call setName on a ServletHolder and pass that it to addServletWithMapping.

        However, I am now sprinkling a few more hashcodes into automatic names - even though this is a poor solution as hashcodes
        are not guaranteed to be unique.

        Show
        Greg Wilkins added a comment - Note that you can always call setName on a ServletHolder and pass that it to addServletWithMapping. However, I am now sprinkling a few more hashcodes into automatic names - even though this is a poor solution as hashcodes are not guaranteed to be unique.
        Greg Wilkins made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Resolution Fixed [ 1 ]

          People

          • Assignee:
            Unassigned
            Reporter:
            Matt Sheppard
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: