Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » tomcat » util » http » mapper » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package org.apache.tomcat.util.http.mapper;
   19   
   20   import javax.naming.NamingException;
   21   import javax.naming.directory.DirContext;
   22   
   23   import org.apache.tomcat.util.buf.CharChunk;
   24   import org.apache.tomcat.util.buf.MessageBytes;
   25   import org.apache.tomcat.util.buf.Ascii;
   26   import java.util.List;
   27   import java.util.ArrayList;
   28   
   29   /**
   30    * Mapper, which implements the servlet API mapping rules (which are derived
   31    * from the HTTP rules).
   32    *
   33    * @author Remy Maucherat
   34    */
   35   public final class Mapper {
   36   
   37   
   38       private static org.apache.juli.logging.Log logger =
   39           org.apache.juli.logging.LogFactory.getLog(Mapper.class);
   40       // ----------------------------------------------------- Instance Variables
   41   
   42   
   43       /**
   44        * Array containing the virtual hosts definitions.
   45        */
   46       protected Host[] hosts = new Host[0];
   47   
   48   
   49       /**
   50        * Default host name.
   51        */
   52       protected String defaultHostName = null;
   53   
   54       /**
   55        * Context associated with this wrapper, used for wrapper mapping.
   56        */
   57       protected Context context = new Context();
   58   
   59   
   60       // --------------------------------------------------------- Public Methods
   61   
   62   
   63       /**
   64        * Get default host.
   65        *
   66        * @return Default host name
   67        */
   68       public String getDefaultHostName() {
   69           return defaultHostName;
   70       }
   71   
   72   
   73       /**
   74        * Set default host.
   75        *
   76        * @param defaultHostName Default host name
   77        */
   78       public void setDefaultHostName(String defaultHostName) {
   79           this.defaultHostName = defaultHostName;
   80       }
   81   
   82       /**
   83        * Add a new host to the mapper.
   84        *
   85        * @param name Virtual host name
   86        * @param host Host object
   87        */
   88       public synchronized void addHost(String name, String[] aliases,
   89                                        Object host) {
   90           Host[] newHosts = new Host[hosts.length + 1];
   91           Host newHost = new Host();
   92           ContextList contextList = new ContextList();
   93           newHost.name = name;
   94           newHost.contextList = contextList;
   95           newHost.object = host;
   96           if (insertMap(hosts, newHosts, newHost)) {
   97               hosts = newHosts;
   98           }
   99           for (int i = 0; i < aliases.length; i++) {
  100               newHosts = new Host[hosts.length + 1];
  101               newHost = new Host();
  102               newHost.name = aliases[i];
  103               newHost.contextList = contextList;
  104               newHost.object = host;
  105               if (insertMap(hosts, newHosts, newHost)) {
  106                   hosts = newHosts;
  107               }
  108           }
  109       }
  110   
  111   
  112       /**
  113        * Remove a host from the mapper.
  114        *
  115        * @param name Virtual host name
  116        */
  117       public synchronized void removeHost(String name) {
  118           // Find and remove the old host
  119           int pos = find(hosts, name);
  120           if (pos < 0) {
  121               return;
  122           }
  123           Object host = hosts[pos].object;
  124           Host[] newHosts = new Host[hosts.length - 1];
  125           if (removeMap(hosts, newHosts, name)) {
  126               hosts = newHosts;
  127           }
  128           // Remove all aliases (they will map to the same host object)
  129           for (int i = 0; i < newHosts.length; i++) {
  130               if (newHosts[i].object == host) {
  131                   Host[] newHosts2 = new Host[hosts.length - 1];
  132                   if (removeMap(hosts, newHosts2, newHosts[i].name)) {
  133                       hosts = newHosts2;
  134                   }
  135               }
  136           }
  137       }
  138   
  139       public String[] getHosts() {
  140           String hostN[] = new String[hosts.length];
  141           for( int i = 0; i < hosts.length; i++ ) {
  142               hostN[i] = hosts[i].name;
  143           }
  144           return hostN;
  145       }
  146   
  147   
  148       /**
  149        * Set context, used for wrapper mapping (request dispatcher).
  150        *
  151        * @param welcomeResources Welcome files defined for this context
  152        * @param resources Static resources of the context
  153        */
  154       public void setContext(String path, String[] welcomeResources,
  155                              javax.naming.Context resources) {
  156           context.name = path;
  157           context.welcomeResources = welcomeResources;
  158           context.resources = resources;
  159       }
  160   
  161   
  162       /**
  163        * Add a new Context to an existing Host.
  164        *
  165        * @param hostName Virtual host name this context belongs to
  166        * @param path Context path
  167        * @param context Context object
  168        * @param welcomeResources Welcome files defined for this context
  169        * @param resources Static resources of the context
  170        */
  171       public void addContext
  172           (String hostName, String path, Object context,
  173            String[] welcomeResources, javax.naming.Context resources) {
  174   
  175           Host[] hosts = this.hosts;
  176           int pos = find(hosts, hostName);
  177           if( pos <0 ) {
  178               addHost(hostName, new String[0], "");
  179               hosts = this.hosts;
  180               pos = find(hosts, hostName);
  181           }
  182           if (pos < 0) {
  183               logger.error("No host found: " + hostName);
  184           }
  185           Host host = hosts[pos];
  186           if (host.name.equals(hostName)) {
  187               int slashCount = slashCount(path);
  188               synchronized (host) {
  189                   Context[] contexts = host.contextList.contexts;
  190                   // Update nesting
  191                   if (slashCount > host.contextList.nesting) {
  192                       host.contextList.nesting = slashCount;
  193                   }
  194                   Context[] newContexts = new Context[contexts.length + 1];
  195                   Context newContext = new Context();
  196                   newContext.name = path;
  197                   newContext.object = context;
  198                   newContext.welcomeResources = welcomeResources;
  199                   newContext.resources = resources;
  200                   if (insertMap(contexts, newContexts, newContext)) {
  201                       host.contextList.contexts = newContexts;
  202                   }
  203               }
  204           }
  205   
  206       }
  207   
  208   
  209       /**
  210        * Remove a context from an existing host.
  211        *
  212        * @param hostName Virtual host name this context belongs to
  213        * @param path Context path
  214        */
  215       public void removeContext(String hostName, String path) {
  216           Host[] hosts = this.hosts;
  217           int pos = find(hosts, hostName);
  218           if (pos < 0) {
  219               return;
  220           }
  221           Host host = hosts[pos];
  222           if (host.name.equals(hostName)) {
  223               synchronized (host) {
  224                   Context[] contexts = host.contextList.contexts;
  225                   if( contexts.length == 0 ){
  226                       return;
  227                   }
  228                   Context[] newContexts = new Context[contexts.length - 1];
  229                   if (removeMap(contexts, newContexts, path)) {
  230                       host.contextList.contexts = newContexts;
  231                       // Recalculate nesting
  232                       host.contextList.nesting = 0;
  233                       for (int i = 0; i < newContexts.length; i++) {
  234                           int slashCount = slashCount(newContexts[i].name);
  235                           if (slashCount > host.contextList.nesting) {
  236                               host.contextList.nesting = slashCount;
  237                           }
  238                       }
  239                   }
  240               }
  241           }
  242       }
  243   
  244   
  245       /**
  246        * Return all contexts, in //HOST/PATH form
  247        *
  248        * @return The context names
  249        */
  250       public String[] getContextNames() {
  251           List list=new ArrayList();
  252           for( int i=0; i<hosts.length; i++ ) {
  253               for( int j=0; j<hosts[i].contextList.contexts.length; j++ ) {
  254                   String cname=hosts[i].contextList.contexts[j].name;
  255                   list.add("//" + hosts[i].name +
  256                           (cname.startsWith("/") ? cname : "/"));
  257               }
  258           }
  259           String res[] = new String[list.size()];
  260           return (String[])list.toArray(res);
  261       }
  262   
  263   
  264       /**
  265        * Add a new Wrapper to an existing Context.
  266        *
  267        * @param hostName Virtual host name this wrapper belongs to
  268        * @param contextPath Context path this wrapper belongs to
  269        * @param path Wrapper mapping
  270        * @param wrapper Wrapper object
  271        */
  272       public void addWrapper(String hostName, String contextPath, String path,
  273                              Object wrapper) {
  274           addWrapper(hostName, contextPath, path, wrapper, false);
  275       }
  276   
  277   
  278       public void addWrapper(String hostName, String contextPath, String path,
  279                              Object wrapper, boolean jspWildCard) {
  280           Host[] hosts = this.hosts;
  281           int pos = find(hosts, hostName);
  282           if (pos < 0) {
  283               return;
  284           }
  285           Host host = hosts[pos];
  286           if (host.name.equals(hostName)) {
  287               Context[] contexts = host.contextList.contexts;
  288               int pos2 = find(contexts, contextPath);
  289               if( pos2<0 ) {
  290                   logger.error("No context found: " + contextPath );
  291                   return;
  292               }
  293               Context context = contexts[pos2];
  294               if (context.name.equals(contextPath)) {
  295                   addWrapper(context, path, wrapper, jspWildCard);
  296               }
  297           }
  298       }
  299   
  300   
  301       /**
  302        * Add a wrapper to the context associated with this wrapper.
  303        *
  304        * @param path Wrapper mapping
  305        * @param wrapper The Wrapper object
  306        */
  307       public void addWrapper(String path, Object wrapper) {
  308           addWrapper(context, path, wrapper);
  309       }
  310   
  311   
  312       public void addWrapper(String path, Object wrapper, boolean jspWildCard) {
  313           addWrapper(context, path, wrapper, jspWildCard);
  314       }
  315   
  316   
  317       protected void addWrapper(Context context, String path, Object wrapper) {
  318           addWrapper(context, path, wrapper, false);
  319       }
  320   
  321   
  322       /**
  323        * Adds a wrapper to the given context.
  324        *
  325        * @param context The context to which to add the wrapper
  326        * @param path Wrapper mapping
  327        * @param wrapper The Wrapper object
  328        * @param jspWildCard true if the wrapper corresponds to the JspServlet
  329        * and the mapping path contains a wildcard; false otherwise
  330        */
  331       protected void addWrapper(Context context, String path, Object wrapper,
  332                                 boolean jspWildCard) {
  333   
  334           synchronized (context) {
  335               Wrapper newWrapper = new Wrapper();
  336               newWrapper.object = wrapper;
  337               newWrapper.jspWildCard = jspWildCard;
  338               if (path.endsWith("/*")) {
  339                   // Wildcard wrapper
  340                   newWrapper.name = path.substring(0, path.length() - 2);
  341                   Wrapper[] oldWrappers = context.wildcardWrappers;
  342                   Wrapper[] newWrappers =
  343                       new Wrapper[oldWrappers.length + 1];
  344                   if (insertMap(oldWrappers, newWrappers, newWrapper)) {
  345                       context.wildcardWrappers = newWrappers;
  346                       int slashCount = slashCount(newWrapper.name);
  347                       if (slashCount > context.nesting) {
  348                           context.nesting = slashCount;
  349                       }
  350                   }
  351               } else if (path.startsWith("*.")) {
  352                   // Extension wrapper
  353                   newWrapper.name = path.substring(2);
  354                   Wrapper[] oldWrappers = context.extensionWrappers;
  355                   Wrapper[] newWrappers =
  356                       new Wrapper[oldWrappers.length + 1];
  357                   if (insertMap(oldWrappers, newWrappers, newWrapper)) {
  358                       context.extensionWrappers = newWrappers;
  359                   }
  360               } else if (path.equals("/")) {
  361                   // Default wrapper
  362                   newWrapper.name = "";
  363                   context.defaultWrapper = newWrapper;
  364               } else {
  365                   // Exact wrapper
  366                   newWrapper.name = path;
  367                   Wrapper[] oldWrappers = context.exactWrappers;
  368                   Wrapper[] newWrappers =
  369                       new Wrapper[oldWrappers.length + 1];
  370                   if (insertMap(oldWrappers, newWrappers, newWrapper)) {
  371                       context.exactWrappers = newWrappers;
  372                   }
  373               }
  374           }
  375       }
  376   
  377   
  378       /**
  379        * Remove a wrapper from the context associated with this wrapper.
  380        *
  381        * @param path Wrapper mapping
  382        */
  383       public void removeWrapper(String path) {
  384           removeWrapper(context, path);
  385       }
  386   
  387   
  388       /**
  389        * Remove a wrapper from an existing context.
  390        *
  391        * @param hostName Virtual host name this wrapper belongs to
  392        * @param contextPath Context path this wrapper belongs to
  393        * @param path Wrapper mapping
  394        */
  395       public void removeWrapper
  396           (String hostName, String contextPath, String path) {
  397           Host[] hosts = this.hosts;
  398           int pos = find(hosts, hostName);
  399           if (pos < 0) {
  400               return;
  401           }
  402           Host host = hosts[pos];
  403           if (host.name.equals(hostName)) {
  404               Context[] contexts = host.contextList.contexts;
  405               int pos2 = find(contexts, contextPath);
  406               if (pos2 < 0) {
  407                   return;
  408               }
  409               Context context = contexts[pos2];
  410               if (context.name.equals(contextPath)) {
  411                   removeWrapper(context, path);
  412               }
  413           }
  414       }
  415   
  416       protected void removeWrapper(Context context, String path) {
  417           synchronized (context) {
  418               if (path.endsWith("/*")) {
  419                   // Wildcard wrapper
  420                   String name = path.substring(0, path.length() - 2);
  421                   Wrapper[] oldWrappers = context.wildcardWrappers;
  422                   Wrapper[] newWrappers =
  423                       new Wrapper[oldWrappers.length - 1];
  424                   if (removeMap(oldWrappers, newWrappers, name)) {
  425                       // Recalculate nesting
  426                       context.nesting = 0;
  427                       for (int i = 0; i < newWrappers.length; i++) {
  428                           int slashCount = slashCount(newWrappers[i].name);
  429                           if (slashCount > context.nesting) {
  430                               context.nesting = slashCount;
  431                           }
  432                       }
  433                       context.wildcardWrappers = newWrappers;
  434                   }
  435               } else if (path.startsWith("*.")) {
  436                   // Extension wrapper
  437                   String name = path.substring(2);
  438                   Wrapper[] oldWrappers = context.extensionWrappers;
  439                   Wrapper[] newWrappers =
  440                       new Wrapper[oldWrappers.length - 1];
  441                   if (removeMap(oldWrappers, newWrappers, name)) {
  442                       context.extensionWrappers = newWrappers;
  443                   }
  444               } else if (path.equals("/")) {
  445                   // Default wrapper
  446                   context.defaultWrapper = null;
  447               } else {
  448                   // Exact wrapper
  449                   String name = path;
  450                   Wrapper[] oldWrappers = context.exactWrappers;
  451                   Wrapper[] newWrappers =
  452                       new Wrapper[oldWrappers.length - 1];
  453                   if (removeMap(oldWrappers, newWrappers, name)) {
  454                       context.exactWrappers = newWrappers;
  455                   }
  456               }
  457           }
  458       }
  459   
  460       public String getWrappersString( String host, String context ) {
  461           String names[]=getWrapperNames(host, context);
  462           StringBuffer sb=new StringBuffer();
  463           for( int i=0; i<names.length; i++ ) {
  464               sb.append(names[i]).append(":");
  465           }
  466           return sb.toString();
  467       }
  468   
  469       public String[] getWrapperNames( String host, String context ) {
  470           List list=new ArrayList();
  471           if( host==null ) host="";
  472           if( context==null ) context="";
  473           for( int i=0; i<hosts.length; i++ ) {
  474               if( ! host.equals( hosts[i].name ))
  475                   continue;
  476               for( int j=0; j<hosts[i].contextList.contexts.length; j++ ) {
  477                   if( ! context.equals( hosts[i].contextList.contexts[j].name))
  478                       continue;
  479                   // found the context
  480                   Context ctx=hosts[i].contextList.contexts[j];
  481                   list.add( ctx.defaultWrapper.path);
  482                   for( int k=0; k<ctx.exactWrappers.length; k++ ) {
  483                       list.add( ctx.exactWrappers[k].path);
  484                   }
  485                   for( int k=0; k<ctx.wildcardWrappers.length; k++ ) {
  486                       list.add( ctx.wildcardWrappers[k].path + "*");
  487                   }
  488                   for( int k=0; k<ctx.extensionWrappers.length; k++ ) {
  489                       list.add( "*." + ctx.extensionWrappers[k].path);
  490                   }
  491               }
  492           }
  493           String res[]=new String[list.size()];
  494           return (String[])list.toArray(res);
  495       }
  496   
  497   
  498   
  499       /**
  500        * Map the specified host name and URI, mutating the given mapping data.
  501        *
  502        * @param host Virtual host name
  503        * @param uri URI
  504        * @param mappingData This structure will contain the result of the mapping
  505        *                    operation
  506        */
  507       public void map(MessageBytes host, MessageBytes uri,
  508                       MappingData mappingData)
  509           throws Exception {
  510   
  511           if (host.isNull()) {
  512               host.getCharChunk().append(defaultHostName);
  513           }
  514           host.toChars();
  515           uri.toChars();
  516           internalMap(host.getCharChunk(), uri.getCharChunk(), mappingData);
  517   
  518       }
  519   
  520   
  521       /**
  522        * Map the specified URI relative to the context,
  523        * mutating the given mapping data.
  524        *
  525        * @param uri URI
  526        * @param mappingData This structure will contain the result of the mapping
  527        *                    operation
  528        */
  529       public void map(MessageBytes uri, MappingData mappingData)
  530           throws Exception {
  531   
  532           uri.toChars();
  533           CharChunk uricc = uri.getCharChunk();
  534           uricc.setLimit(-1);
  535           internalMapWrapper(context, uricc, mappingData);
  536   
  537       }
  538   
  539   
  540       // -------------------------------------------------------- Private Methods
  541   
  542   
  543       /**
  544        * Map the specified URI.
  545        */
  546       private final void internalMap(CharChunk host, CharChunk uri,
  547                                      MappingData mappingData)
  548           throws Exception {
  549   
  550           uri.setLimit(-1);
  551   
  552           Context[] contexts = null;
  553           Context context = null;
  554           int nesting = 0;
  555   
  556           // Virtual host mapping
  557           if (mappingData.host == null) {
  558               Host[] hosts = this.hosts;
  559               int pos = findIgnoreCase(hosts, host);
  560               if ((pos != -1) && (host.equalsIgnoreCase(hosts[pos].name))) {
  561                   mappingData.host = hosts[pos].object;
  562                   contexts = hosts[pos].contextList.contexts;
  563                   nesting = hosts[pos].contextList.nesting;
  564               } else {
  565                   if (defaultHostName == null) {
  566                       return;
  567                   }
  568                   pos = find(hosts, defaultHostName);
  569                   if ((pos != -1) && (defaultHostName.equals(hosts[pos].name))) {
  570                       mappingData.host = hosts[pos].object;
  571                       contexts = hosts[pos].contextList.contexts;
  572                       nesting = hosts[pos].contextList.nesting;
  573                   } else {
  574                       return;
  575                   }
  576               }
  577           }
  578   
  579           // Context mapping
  580           if (mappingData.context == null) {
  581               int pos = find(contexts, uri);
  582               if (pos == -1) {
  583                   return;
  584               }
  585   
  586               int lastSlash = -1;
  587               int uriEnd = uri.getEnd();
  588               int length = -1;
  589               boolean found = false;
  590               while (pos >= 0) {
  591                   if (uri.startsWith(contexts[pos].name)) {
  592                       length = contexts[pos].name.length();
  593                       if (uri.getLength() == length) {
  594                           found = true;
  595                           break;
  596                       } else if (uri.startsWithIgnoreCase("/", length)) {
  597                           found = true;
  598                           break;
  599                       }
  600                   }
  601                   if (lastSlash == -1) {
  602                       lastSlash = nthSlash(uri, nesting + 1);
  603                   } else {
  604                       lastSlash = lastSlash(uri);
  605                   }
  606                   uri.setEnd(lastSlash);
  607                   pos = find(contexts, uri);
  608               }
  609               uri.setEnd(uriEnd);
  610   
  611               if (!found) {
  612                   if (contexts[0].name.equals("")) {
  613                       context = contexts[0];
  614                   }
  615               } else {
  616                   context = contexts[pos];
  617               }
  618               if (context != null) {
  619                   mappingData.context = context.object;
  620                   mappingData.contextPath.setString(context.name);
  621               }
  622           }
  623   
  624           // Wrapper mapping
  625           if ((context != null) && (mappingData.wrapper == null)) {
  626               internalMapWrapper(context, uri, mappingData);
  627           }
  628   
  629       }
  630   
  631   
  632       /**
  633        * Wrapper mapping.
  634        */
  635       private final void internalMapWrapper(Context context, CharChunk path,
  636                                             MappingData mappingData)
  637           throws Exception {
  638   
  639           int pathOffset = path.getOffset();
  640           int pathEnd = path.getEnd();
  641           int servletPath = pathOffset;
  642           boolean noServletPath = false;
  643   
  644           int length = context.name.length();
  645           if (length != (pathEnd - pathOffset)) {
  646               servletPath = pathOffset + length;
  647           } else {
  648               noServletPath = true;
  649               path.append('/');
  650               pathOffset = path.getOffset();
  651               pathEnd = path.getEnd();
  652               servletPath = pathOffset+length;
  653           }
  654   
  655           path.setOffset(servletPath);
  656   
  657           // Rule 1 -- Exact Match
  658           Wrapper[] exactWrappers = context.exactWrappers;
  659           internalMapExactWrapper(exactWrappers, path, mappingData);
  660   
  661           // Rule 2 -- Prefix Match
  662           boolean checkJspWelcomeFiles = false;
  663           Wrapper[] wildcardWrappers = context.wildcardWrappers;
  664           if (mappingData.wrapper == null) {
  665               internalMapWildcardWrapper(wildcardWrappers, context.nesting, 
  666                                          path, mappingData);
  667               if (mappingData.wrapper != null && mappingData.jspWildCard) {
  668                   char[] buf = path.getBuffer();
  669                   if (buf[pathEnd - 1] == '/') {
  670                       /*
  671                        * Path ending in '/' was mapped to JSP servlet based on
  672                        * wildcard match (e.g., as specified in url-pattern of a
  673                        * jsp-property-group.
  674                        * Force the context's welcome files, which are interpreted
  675                        * as JSP files (since they match the url-pattern), to be
  676                        * considered. See Bugzilla 27664.
  677                        */ 
  678                       mappingData.wrapper = null;
  679                       checkJspWelcomeFiles = true;
  680                   } else {
  681                       // See Bugzilla 27704
  682                       mappingData.wrapperPath.setChars(buf, path.getStart(),
  683                                                        path.getLength());
  684                       mappingData.pathInfo.recycle();
  685                   }
  686               }
  687           }
  688   
  689           if(mappingData.wrapper == null && noServletPath) {
  690               // The path is empty, redirect to "/"
  691               mappingData.redirectPath.setChars
  692                   (path.getBuffer(), pathOffset, pathEnd);
  693               path.setEnd(pathEnd - 1);
  694               return;
  695           }
  696   
  697           // Rule 3 -- Extension Match
  698           Wrapper[] extensionWrappers = context.extensionWrappers;
  699           if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
  700               internalMapExtensionWrapper(extensionWrappers, path, mappingData);
  701           }
  702   
  703           // Rule 4 -- Welcome resources processing for servlets
  704           if (mappingData.wrapper == null) {
  705               boolean checkWelcomeFiles = checkJspWelcomeFiles;
  706               if (!checkWelcomeFiles) {
  707                   char[] buf = path.getBuffer();
  708                   checkWelcomeFiles = (buf[pathEnd - 1] == '/');
  709               }
  710               if (checkWelcomeFiles) {
  711                   for (int i = 0; (i < context.welcomeResources.length)
  712                            && (mappingData.wrapper == null); i++) {
  713                       path.setOffset(pathOffset);
  714                       path.setEnd(pathEnd);
  715                       path.append(context.welcomeResources[i], 0,
  716                                   context.welcomeResources[i].length());
  717                       path.setOffset(servletPath);
  718   
  719                       // Rule 4a -- Welcome resources processing for exact macth
  720                       internalMapExactWrapper(exactWrappers, path, mappingData);
  721   
  722                       // Rule 4b -- Welcome resources processing for prefix match
  723                       if (mappingData.wrapper == null) {
  724                           internalMapWildcardWrapper
  725                               (wildcardWrappers, context.nesting, 
  726                                path, mappingData);
  727                       }
  728   
  729                       // Rule 4c -- Welcome resources processing
  730                       //            for physical folder
  731                       if (mappingData.wrapper == null
  732                           && context.resources != null) {
  733                           Object file = null;
  734                           String pathStr = path.toString();
  735                           try {
  736                               file = context.resources.lookup(pathStr);
  737                           } catch(NamingException nex) {
  738                               // Swallow not found, since this is normal
  739                           }
  740                           if (file != null && !(file instanceof DirContext) ) {
  741                               internalMapExtensionWrapper(extensionWrappers,
  742                                                           path, mappingData);
  743                               if (mappingData.wrapper == null
  744                                   && context.defaultWrapper != null) {
  745                                   mappingData.wrapper =
  746                                       context.defaultWrapper.object;
  747                                   mappingData.requestPath.setChars
  748                                       (path.getBuffer(), path.getStart(), 
  749                                        path.getLength());
  750                                   mappingData.wrapperPath.setChars
  751                                       (path.getBuffer(), path.getStart(), 
  752                                        path.getLength());
  753                                   mappingData.requestPath.setString(pathStr);
  754                                   mappingData.wrapperPath.setString(pathStr);
  755                               }
  756                           }
  757                       }
  758                   }
  759   
  760                   path.setOffset(servletPath);
  761                   path.setEnd(pathEnd);
  762               }
  763                                           
  764           }
  765   
  766   
  767           // Rule 7 -- Default servlet
  768           if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
  769               if (context.defaultWrapper != null) {
  770                   mappingData.wrapper = context.defaultWrapper.object;
  771                   mappingData.requestPath.setChars
  772                       (path.getBuffer(), path.getStart(), path.getLength());
  773                   mappingData.wrapperPath.setChars
  774                       (path.getBuffer(), path.getStart(), path.getLength());
  775               }
  776               // Redirection to a folder
  777               char[] buf = path.getBuffer();
  778               if (context.resources != null && buf[pathEnd -1 ] != '/') {
  779                   Object file = null;
  780                   String pathStr = path.toString();
  781                   try {
  782                       file = context.resources.lookup(pathStr);
  783                   } catch(NamingException nex) {
  784                       // Swallow, since someone else handles the 404
  785                   }
  786                   if (file != null && file instanceof DirContext) {
  787                       // Note: this mutates the path: do not do any processing 
  788                       // after this (since we set the redirectPath, there 
  789                       // shouldn't be any)
  790                       path.setOffset(pathOffset);
  791                       path.append('/');
  792                       mappingData.redirectPath.setChars
  793                           (path.getBuffer(), path.getStart(), path.getLength());
  794                   } else {
  795                       mappingData.requestPath.setString(pathStr);
  796                       mappingData.wrapperPath.setString(pathStr);
  797                   }
  798               }
  799           }
  800   
  801           path.setOffset(pathOffset);
  802           path.setEnd(pathEnd);
  803   
  804       }
  805   
  806   
  807       /**
  808        * Exact mapping.
  809        */
  810       private final void internalMapExactWrapper
  811           (Wrapper[] wrappers, CharChunk path, MappingData mappingData) {
  812           int pos = find(wrappers, path);
  813           if ((pos != -1) && (path.equals(wrappers[pos].name))) {
  814               mappingData.requestPath.setString(wrappers[pos].name);
  815               mappingData.wrapperPath.setString(wrappers[pos].name);
  816               mappingData.wrapper = wrappers[pos].object;
  817           }
  818       }
  819   
  820   
  821       /**
  822        * Wildcard mapping.
  823        */
  824       private final void internalMapWildcardWrapper
  825           (Wrapper[] wrappers, int nesting, CharChunk path, 
  826            MappingData mappingData) {
  827   
  828           int pathEnd = path.getEnd();
  829           int pathOffset = path.getOffset();
  830   
  831           int lastSlash = -1;
  832           int length = -1;
  833           int pos = find(wrappers, path);
  834           if (pos != -1) {
  835               boolean found = false;
  836               while (pos >= 0) {
  837                   if (path.startsWith(wrappers[pos].name)) {
  838                       length = wrappers[pos].name.length();
  839                       if (path.getLength() == length) {
  840                           found = true;
  841                           break;
  842                       } else if (path.startsWithIgnoreCase("/", length)) {
  843                           found = true;
  844                           break;
  845                       }
  846                   }
  847                   if (lastSlash == -1) {
  848                       lastSlash = nthSlash(path, nesting + 1);
  849                   } else {
  850                       lastSlash = lastSlash(path);
  851                   }
  852                   path.setEnd(lastSlash);
  853                   pos = find(wrappers, path);
  854               }
  855               path.setEnd(pathEnd);
  856               if (found) {
  857                   mappingData.wrapperPath.setString(wrappers[pos].name);
  858                   if (path.getLength() > length) {
  859                       mappingData.pathInfo.setChars
  860                           (path.getBuffer(),
  861                            path.getOffset() + length,
  862                            path.getLength() - length);
  863                   }
  864                   mappingData.requestPath.setChars
  865                       (path.getBuffer(), path.getOffset(), path.getLength());
  866                   mappingData.wrapper = wrappers[pos].object;
  867                   mappingData.jspWildCard = wrappers[pos].jspWildCard;
  868               }
  869           }
  870       }
  871   
  872   
  873       /**
  874        * Extension mappings.
  875        */
  876       private final void internalMapExtensionWrapper
  877           (Wrapper[] wrappers, CharChunk path, MappingData mappingData) {
  878           char[] buf = path.getBuffer();
  879           int pathEnd = path.getEnd();
  880           int servletPath = path.getOffset();
  881           int slash = -1;
  882           for (int i = pathEnd - 1; i >= servletPath; i--) {
  883               if (buf[i] == '/') {
  884                   slash = i;
  885                   break;
  886               }
  887           }
  888           if (slash >= 0) {
  889               int period = -1;
  890               for (int i = pathEnd - 1; i > slash; i--) {
  891                   if (buf[i] == '.') {
  892                       period = i;
  893                       break;
  894                   }
  895               }
  896               if (period >= 0) {
  897                   path.setOffset(period + 1);
  898                   path.setEnd(pathEnd);
  899                   int pos = find(wrappers, path);
  900                   if ((pos != -1)
  901                       && (path.equals(wrappers[pos].name))) {
  902                       mappingData.wrapperPath.setChars
  903                           (buf, servletPath, pathEnd - servletPath);
  904                       mappingData.requestPath.setChars
  905                           (buf, servletPath, pathEnd - servletPath);
  906                       mappingData.wrapper = wrappers[pos].object;
  907                   }
  908                   path.setOffset(servletPath);
  909                   path.setEnd(pathEnd);
  910               }
  911           }
  912       }
  913   
  914   
  915       /**
  916        * Find a map elemnt given its name in a sorted array of map elements.
  917        * This will return the index for the closest inferior or equal item in the
  918        * given array.
  919        */
  920       private static final int find(MapElement[] map, CharChunk name) {
  921           return find(map, name, name.getStart(), name.getEnd());
  922       }
  923   
  924   
  925       /**
  926        * Find a map elemnt given its name in a sorted array of map elements.
  927        * This will return the index for the closest inferior or equal item in the
  928        * given array.
  929        */
  930       private static final int find(MapElement[] map, CharChunk name,
  931                                     int start, int end) {
  932   
  933           int a = 0;
  934           int b = map.length - 1;
  935   
  936           // Special cases: -1 and 0
  937           if (b == -1) {
  938               return -1;
  939           }
  940           
  941           if (compare(name, start, end, map[0].name) < 0 ) {
  942               return -1;
  943           }         
  944           if (b == 0) {
  945               return 0;
  946           }
  947   
  948           int i = 0;
  949           while (true) {
  950               i = (b + a) / 2;
  951               int result = compare(name, start, end, map[i].name);
  952               if (result == 1) {
  953                   a = i;
  954               } else if (result == 0) {
  955                   return i;
  956               } else {
  957                   b = i;
  958               }
  959               if ((b - a) == 1) {
  960                   int result2 = compare(name, start, end, map[b].name);
  961                   if (result2 < 0) {
  962                       return a;
  963                   } else {
  964                       return b;
  965                   }
  966               }
  967           }
  968   
  969       }
  970   
  971       /**
  972        * Find a map elemnt given its name in a sorted array of map elements.
  973        * This will return the index for the closest inferior or equal item in the
  974        * given array.
  975        */
  976       private static final int findIgnoreCase(MapElement[] map, CharChunk name) {
  977           return findIgnoreCase(map, name, name.getStart(), name.getEnd());
  978       }
  979   
  980   
  981       /**
  982        * Find a map elemnt given its name in a sorted array of map elements.
  983        * This will return the index for the closest inferior or equal item in the
  984        * given array.
  985        */
  986       private static final int findIgnoreCase(MapElement[] map, CharChunk name,
  987                                     int start, int end) {
  988   
  989           int a = 0;
  990           int b = map.length - 1;
  991   
  992           // Special cases: -1 and 0
  993           if (b == -1) {
  994               return -1;
  995           }
  996           if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) {
  997               return -1;
  998           }         
  999           if (b == 0) {
 1000               return 0;
 1001           }
 1002   
 1003           int i = 0;
 1004           while (true) {
 1005               i = (b + a) / 2;
 1006               int result = compareIgnoreCase(name, start, end, map[i].name);
 1007               if (result == 1) {
 1008                   a = i;
 1009               } else if (result == 0) {
 1010                   return i;
 1011               } else {
 1012                   b = i;
 1013               }
 1014               if ((b - a) == 1) {
 1015                   int result2 = compareIgnoreCase(name, start, end, map[b].name);
 1016                   if (result2 < 0) {
 1017                       return a;
 1018                   } else {
 1019                       return b;
 1020                   }
 1021               }
 1022           }
 1023   
 1024       }
 1025   
 1026   
 1027       /**
 1028        * Find a map elemnt given its name in a sorted array of map elements.
 1029        * This will return the index for the closest inferior or equal item in the
 1030        * given array.
 1031        */
 1032       private static final int find(MapElement[] map, String name) {
 1033   
 1034           int a = 0;
 1035           int b = map.length - 1;
 1036   
 1037           // Special cases: -1 and 0
 1038           if (b == -1) {
 1039               return -1;
 1040           }
 1041           
 1042           if (name.compareTo(map[0].name) < 0) {
 1043               return -1;
 1044           } 
 1045           if (b == 0) {
 1046               return 0;
 1047           }
 1048   
 1049           int i = 0;
 1050           while (true) {
 1051               i = (b + a) / 2;
 1052               int result = name.compareTo(map[i].name);
 1053               if (result > 0) {
 1054                   a = i;
 1055               } else if (result == 0) {
 1056                   return i;
 1057               } else {
 1058                   b = i;
 1059               }
 1060               if ((b - a) == 1) {
 1061                   int result2 = name.compareTo(map[b].name);
 1062                   if (result2 < 0) {
 1063                       return a;
 1064                   } else {
 1065                       return b;
 1066                   }
 1067               }
 1068           }
 1069   
 1070       }
 1071   
 1072   
 1073       /**
 1074        * Compare given char chunk with String.
 1075        * Return -1, 0 or +1 if inferior, equal, or superior to the String.
 1076        */
 1077       private static final int compare(CharChunk name, int start, int end,
 1078                                        String compareTo) {
 1079           int result = 0;
 1080           char[] c = name.getBuffer();
 1081           int len = compareTo.length();
 1082           if ((end - start) < len) {
 1083               len = end - start;
 1084           }
 1085           for (int i = 0; (i < len) && (result == 0); i++) {
 1086               if (c[i + start] > compareTo.charAt(i)) {
 1087                   result = 1;
 1088               } else if (c[i + start] < compareTo.charAt(i)) {
 1089                   result = -1;
 1090               }
 1091           }
 1092           if (result == 0) {
 1093               if (compareTo.length() > (end - start)) {
 1094                   result = -1;
 1095               } else if (compareTo.length() < (end - start)) {
 1096                   result = 1;
 1097               }
 1098           }
 1099           return result;
 1100       }
 1101   
 1102   
 1103       /**
 1104        * Compare given char chunk with String ignoring case.
 1105        * Return -1, 0 or +1 if inferior, equal, or superior to the String.
 1106        */
 1107       private static final int compareIgnoreCase(CharChunk name, int start, int end,
 1108                                        String compareTo) {
 1109           int result = 0;
 1110           char[] c = name.getBuffer();
 1111           int len = compareTo.length();
 1112           if ((end - start) < len) {
 1113               len = end - start;
 1114           }
 1115           for (int i = 0; (i < len) && (result == 0); i++) {
 1116               if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) {
 1117                   result = 1;
 1118               } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) {
 1119                   result = -1;
 1120               }
 1121           }
 1122           if (result == 0) {
 1123               if (compareTo.length() > (end - start)) {
 1124                   result = -1;
 1125               } else if (compareTo.length() < (end - start)) {
 1126                   result = 1;
 1127               }
 1128           }
 1129           return result;
 1130       }
 1131   
 1132   
 1133       /**
 1134        * Find the position of the last slash in the given char chunk.
 1135        */
 1136       private static final int lastSlash(CharChunk name) {
 1137   
 1138           char[] c = name.getBuffer();
 1139           int end = name.getEnd();
 1140           int start = name.getStart();
 1141           int pos = end;
 1142   
 1143           while (pos > start) {
 1144               if (c[--pos] == '/') {
 1145                   break;
 1146               }
 1147           }
 1148   
 1149           return (pos);
 1150   
 1151       }
 1152   
 1153   
 1154       /**
 1155        * Find the position of the nth slash, in the given char chunk.
 1156        */
 1157       private static final int nthSlash(CharChunk name, int n) {
 1158   
 1159           char[] c = name.getBuffer();
 1160           int end = name.getEnd();
 1161           int start = name.getStart();
 1162           int pos = start;
 1163           int count = 0;
 1164   
 1165           while (pos < end) {
 1166               if ((c[pos++] == '/') && ((++count) == n)) {
 1167                   pos--;
 1168                   break;
 1169               }
 1170           }
 1171   
 1172           return (pos);
 1173   
 1174       }
 1175   
 1176   
 1177       /**
 1178        * Return the slash count in a given string.
 1179        */
 1180       private static final int slashCount(String name) {
 1181           int pos = -1;
 1182           int count = 0;
 1183           while ((pos = name.indexOf('/', pos + 1)) != -1) {
 1184               count++;
 1185           }
 1186           return count;
 1187       }
 1188   
 1189   
 1190       /**
 1191        * Insert into the right place in a sorted MapElement array, and prevent
 1192        * duplicates.
 1193        */
 1194       private static final boolean insertMap
 1195           (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) {
 1196           int pos = find(oldMap, newElement.name);
 1197           if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) {
 1198               return false;
 1199           }
 1200           System.arraycopy(oldMap, 0, newMap, 0, pos + 1);
 1201           newMap[pos + 1] = newElement;
 1202           System.arraycopy
 1203               (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1);
 1204           return true;
 1205       }
 1206   
 1207   
 1208       /**
 1209        * Insert into the right place in a sorted MapElement array.
 1210        */
 1211       private static final boolean removeMap
 1212           (MapElement[] oldMap, MapElement[] newMap, String name) {
 1213           int pos = find(oldMap, name);
 1214           if ((pos != -1) && (name.equals(oldMap[pos].name))) {
 1215               System.arraycopy(oldMap, 0, newMap, 0, pos);
 1216               System.arraycopy(oldMap, pos + 1, newMap, pos,
 1217                                oldMap.length - pos - 1);
 1218               return true;
 1219           }
 1220           return false;
 1221       }
 1222   
 1223   
 1224       // ------------------------------------------------- MapElement Inner Class
 1225   
 1226   
 1227       protected static abstract class MapElement {
 1228   
 1229           public String name = null;
 1230           public Object object = null;
 1231   
 1232       }
 1233   
 1234   
 1235       // ------------------------------------------------------- Host Inner Class
 1236   
 1237   
 1238       protected static final class Host
 1239           extends MapElement {
 1240   
 1241           public ContextList contextList = null;
 1242   
 1243       }
 1244   
 1245   
 1246       // ------------------------------------------------ ContextList Inner Class
 1247   
 1248   
 1249       protected static final class ContextList {
 1250   
 1251           public Context[] contexts = new Context[0];
 1252           public int nesting = 0;
 1253   
 1254       }
 1255   
 1256   
 1257       // ---------------------------------------------------- Context Inner Class
 1258   
 1259   
 1260       protected static final class Context
 1261           extends MapElement {
 1262   
 1263           public String path = null;
 1264           public String[] welcomeResources = new String[0];
 1265           public javax.naming.Context resources = null;
 1266           public Wrapper defaultWrapper = null;
 1267           public Wrapper[] exactWrappers = new Wrapper[0];
 1268           public Wrapper[] wildcardWrappers = new Wrapper[0];
 1269           public Wrapper[] extensionWrappers = new Wrapper[0];
 1270           public int nesting = 0;
 1271   
 1272       }
 1273   
 1274   
 1275       // ---------------------------------------------------- Wrapper Inner Class
 1276   
 1277   
 1278       protected static class Wrapper
 1279           extends MapElement {
 1280   
 1281           public String path = null;
 1282           public boolean jspWildCard = false;
 1283       }
 1284   
 1285   
 1286       // -------------------------------------------------------- Testing Methods
 1287   
 1288       // FIXME: Externalize this
 1289       /*
 1290       public static void main(String args[]) {
 1291   
 1292           try {
 1293   
 1294           Mapper mapper = new Mapper();
 1295           System.out.println("Start");
 1296   
 1297           mapper.addHost("sjbjdvwsbvhrb", new String[0], "blah1");
 1298           mapper.addHost("sjbjdvwsbvhr/", new String[0], "blah1");
 1299           mapper.addHost("wekhfewuifweuibf", new String[0], "blah2");
 1300           mapper.addHost("ylwrehirkuewh", new String[0], "blah3");
 1301           mapper.addHost("iohgeoihro", new String[0], "blah4");
 1302           mapper.addHost("fwehoihoihwfeo", new String[0], "blah5");
 1303           mapper.addHost("owefojiwefoi", new String[0], "blah6");
 1304           mapper.addHost("iowejoiejfoiew", new String[0], "blah7");
 1305           mapper.addHost("iowejoiejfoiew", new String[0], "blah17");
 1306           mapper.addHost("ohewoihfewoih", new String[0], "blah8");
 1307           mapper.addHost("fewohfoweoih", new String[0], "blah9");
 1308           mapper.addHost("ttthtiuhwoih", new String[0], "blah10");
 1309           mapper.addHost("lkwefjwojweffewoih", new String[0], "blah11");
 1310           mapper.addHost("zzzuyopjvewpovewjhfewoih", new String[0], "blah12");
 1311           mapper.addHost("xxxxgqwiwoih", new String[0], "blah13");
 1312           mapper.addHost("qwigqwiwoih", new String[0], "blah14");
 1313   
 1314           System.out.println("Map:");
 1315           for (int i = 0; i < mapper.hosts.length; i++) {
 1316               System.out.println(mapper.hosts[i].name);
 1317           }
 1318   
 1319           mapper.setDefaultHostName("ylwrehirkuewh");
 1320   
 1321           String[] welcomes = new String[2];
 1322           welcomes[0] = "boo/baba";
 1323           welcomes[1] = "bobou";
 1324   
 1325           mapper.addContext("iowejoiejfoiew", "", "context0", new String[0], null);
 1326           mapper.addContext("iowejoiejfoiew", "/foo", "context1", new String[0], null);
 1327           mapper.addContext("iowejoiejfoiew", "/foo/bar", "context2", welcomes, null);
 1328           mapper.addContext("iowejoiejfoiew", "/foo/bar/bla", "context3", new String[0], null);
 1329   
 1330           mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/fo/*", "wrapper0");
 1331           mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/", "wrapper1");
 1332           mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blh", "wrapper2");
 1333           mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.jsp", "wrapper3");
 1334           mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bou/*", "wrapper4");
 1335           mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bobou/*", "wrapper5");
 1336           mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.htm", "wrapper6");
 1337   
 1338           MappingData mappingData = new MappingData();
 1339           MessageBytes host = MessageBytes.newInstance();
 1340           host.setString("iowejoiejfoiew");
 1341           MessageBytes uri = MessageBytes.newInstance();
 1342           uri.setString("/foo/bar/blah/bobou/foo");
 1343           uri.toChars();
 1344           uri.getCharChunk().setLimit(-1);
 1345   
 1346           mapper.map(host, uri, mappingData);
 1347           System.out.println("MD Host:" + mappingData.host);
 1348           System.out.println("MD Context:" + mappingData.context);
 1349           System.out.println("MD Wrapper:" + mappingData.wrapper);
 1350   
 1351           System.out.println("contextPath:" + mappingData.contextPath);
 1352           System.out.println("wrapperPath:" + mappingData.wrapperPath);
 1353           System.out.println("pathInfo:" + mappingData.pathInfo);
 1354           System.out.println("redirectPath:" + mappingData.redirectPath);
 1355   
 1356           mappingData.recycle();
 1357           mapper.map(host, uri, mappingData);
 1358           System.out.println("MD Host:" + mappingData.host);
 1359           System.out.println("MD Context:" + mappingData.context);
 1360           System.out.println("MD Wrapper:" + mappingData.wrapper);
 1361   
 1362           System.out.println("contextPath:" + mappingData.contextPath);
 1363           System.out.println("wrapperPath:" + mappingData.wrapperPath);
 1364           System.out.println("pathInfo:" + mappingData.pathInfo);
 1365           System.out.println("redirectPath:" + mappingData.redirectPath);
 1366   
 1367           for (int i = 0; i < 1000000; i++) {
 1368               mappingData.recycle();
 1369               mapper.map(host, uri, mappingData);
 1370           }
 1371   
 1372           long time = System.currentTimeMillis();
 1373           for (int i = 0; i < 1000000; i++) {
 1374               mappingData.recycle();
 1375               mapper.map(host, uri, mappingData);
 1376           }
 1377           System.out.println("Elapsed:" + (System.currentTimeMillis() - time));
 1378   
 1379           System.out.println("MD Host:" + mappingData.host);
 1380           System.out.println("MD Context:" + mappingData.context);
 1381           System.out.println("MD Wrapper:" + mappingData.wrapper);
 1382   
 1383           System.out.println("contextPath:" + mappingData.contextPath);
 1384           System.out.println("wrapperPath:" + mappingData.wrapperPath);
 1385           System.out.println("requestPath:" + mappingData.requestPath);
 1386           System.out.println("pathInfo:" + mappingData.pathInfo);
 1387           System.out.println("redirectPath:" + mappingData.redirectPath);
 1388   
 1389           } catch (Exception e) {
 1390               e.printStackTrace();
 1391           }
 1392   
 1393       }
 1394       */
 1395   
 1396   
 1397   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » tomcat » util » http » mapper » [javadoc | source]